Coverage for brainbox/video.py: 96%
28 statements
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-08 17:16 +0100
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-08 17:16 +0100
1"""Functions for analyzing video frame data"""
2import numpy as np
3import cv2
6def frame_diff(frame1, frame2):
7 """
8 Outputs pythagorean distance between two frames
9 :param frame1: A numpy array of pixels with a shape of either (m, n, 3) or (m, n)
10 :param frame2: A numpy array of pixels with a shape of either (m, n, 3) or (m, n)
11 :return: An array with a shape equal to the input frames
12 """
13 if frame1.shape != frame2.shape: 1e
14 raise ValueError('Frames must have the same shape') 1e
15 diff32 = np.float32(frame1) - np.float32(frame2) 1e
16 if frame1.ndim == 3: 1e
17 norm32 = (np.sqrt(diff32[:, :, 0] ** 2 + diff32[:, :, 1] ** 2 + diff32[:, :, 2] ** 2) / 1e
18 np.sqrt(255 ** 2 * 3))
19 else:
20 norm32 = np.sqrt(diff32 ** 2 * 3) / np.sqrt(255 ** 2 * 3) 1e
21 return np.uint8(norm32 * 255) 1e
24def frame_diffs(frames, diff=1):
25 """
26 Return the difference between frames. May also take difference between more than 1 frames.
27 Values are normalized between 0-255.
28 :param frames: Array or list of frames, where each frame is either (y, x) or (y, x, 3).
29 :param diff: Take difference between frames N and frames N + diff.
30 :return: uint8 array with shape (n-diff, y, x).
31 """
32 frames = np.array(frames, dtype=np.float32) 1dabc
33 if frames.shape[0] < diff: 1dabc
34 raise ValueError('Difference must be less than number of frames') 1d
35 diff32 = frames[diff:] - frames[:-diff] 1dabc
36 # Normalize
37 if frames.ndim == 4: 1dabc
38 norm32 = np.sqrt((diff32 ** 2).sum(axis=3)) / np.sqrt(255 ** 2 * 3) 1d
39 else:
40 norm32 = np.sqrt(diff32 ** 2 * 3) / np.sqrt(255 ** 2 * 3) 1dabc
41 return np.uint8(norm32 * 255) 1dabc
44def motion_energy(frames, diff=2, kernel=None, normalize=True):
45 """
46 Returns a min-max normalized vector of motion energy between frames.
47 :param frames: A list of ndarray of frames.
48 :param diff: Take difference between frames N and frames N + diff.
49 :param kernel: An optional Gaussian smoothing to apply with a given kernel size.
50 :param normalize: If True, motion energy is min-max normalized
51 :return df_: A vector of length n frames - diff, normalized between 0 and 1.
52 :return stDev: The standard deviation between the frames (not normalized).
54 Example 1 - Calculate normalized difference between consecutive frames
55 df, std = motion_energy(frames, diff=1)
57 Example 2 - Calculate smoothed difference between every 2nd frame
58 df, _ = motion_energy(frames, kernel=(9, 9))
59 """
60 df = frame_diffs(frames, diff) 1abc
62 # Smooth with a Gaussian blur TODO Use median blur instead
63 if kernel is not None: 1abc
64 df = cv2.GaussianBlur(df, (9, 9), 0)
65 stDev = np.array([cv2.meanStdDev(x)[1] for x in df]).squeeze() 1abc
67 # Feature scaling
68 df_ = df.sum(axis=(1, 2)) 1abc
69 if normalize: 1abc
70 df_ = (df_ - df_.min()) / (df_.max() - df_.min()) 1abc
71 return df_, stDev 1abc