I need to detect the high variation of the optical flow in the video. For example the crossroads. Two cars are driving and they have some value of optical flow. Next, in some time period, they have collision, so it will produce a high variation of optical flow. How to detect it?
optical flow with binarization and mask
expecting the result to fire event when the variation of the optical flow high
how to capture this event?
def label_flows(flows):
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0)
flags = cv.KMEANS_RANDOM_CENTERS
h, w = flows.shape[:2]
labeled_flows = []
flows = flows.reshape(h*w, -1)
comp, labels, centers = cv.kmeans(flows, 2, None, criteria, 10, flags)
n = np.sum(labels == 1)
camera_motion_label = np.argmax([labels.size-n, n])
labeled = np.uint8(255*(labels.reshape(h, w) == camera_motion_label))
return labeled
def find_target_in_labeled_flow(labeled_flow):
labeled_flow = cv2.bitwise_not(labeled_flow)
bw = 10
h, w = labeled_flow.shape[:2]
border_cut = labeled_flow[bw:h-bw, bw:w-bw]
conncomp, stats = cv2.connectedComponentsWithStats(border_cut, connectivity=8)[1:3]
target_label = np.argmax(stats[1:, cv2.CC_STAT_AREA]) + 1
img = np.zeros_like(labeled_flow)
img[bw:h-bw, bw:w-bw] = 255*(conncomp == target_label)
return img
def put_optical_flow_arrows_on_image(image, optical_flow_image, threshold=2.0, skip_amount=30):
image = image.copy()
if len(image.shape) == 2:
image = np.stack((image,)*3, axis=2)
flow_start = np.stack(np.meshgrid(range(optical_flow_image.shape[1]), range(optical_flow_image.shape[0])), 2)
flow_end = (optical_flow_image[flow_start[:,:,1],flow_start[:,:,0],:1]*3 + flow_start).astype(np.int32)
norm = np.linalg.norm(flow_end - flow_start, axis=2)
norm[norm < threshold] = 0
nz = np.nonzero(norm)
for i in range(0, len(nz[0]), skip_amount):
y, x = nz[0][i], nz[1][i]
cv.arrowedLine(image,
pt1=tuple(flow_start[y,x]),
pt2=tuple(flow_end[y,x]),
color=(0, 255, 0),
thickness=1,
tipLength=.2)
return image
if __name__ =='__main__':
cap = cv.VideoCapture("video.mp4")
ret, first_frame = cap.read()
prev_gray = cv.cvtColor(first_frame, cv.COLOR_BGR2GRAY)
mask = np.zeros_like(first_frame)
mask[..., 1] = 255
cv.namedWindow('input',cv.WINDOW_NORMAL)
cv.namedWindow('binarized',cv.WINDOW_NORMAL)
cv.namedWindow('dense_optical_flow',cv.WINDOW_NORMAL)
cv.namedWindow('color', cv.WINDOW_NORMAL)
while(cap.isOpened()):
ret, frame = cap.read()
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
flow = cv.calcOpticalFlowFarneback(prev_gray, gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)
magnitude, angle = cv.cartToPolar(flow[..., 0], flow[..., 1])
mask[..., 0] = angle * 180 / np.pi / 2
mask[..., 2] = cv.normalize(magnitude, None, 0, 255, cv.NORM_MINMAX)
rgb = cv.cvtColor(mask, cv.COLOR_HSV2BGR)
binary_flow = label_flows(flow)
optical_flow_arrows = put_optical_flow_arrows_on_image(gray, flow)
hsv = cv.cvtColor(optical_flow_arrows, cv.COLOR_BGR2HSV)
mask_green = cv.inRange(hsv, (36, 25, 25), (70, 255,255))
imask = mask_green>0
green = np.zeros_like(optical_flow_arrows, np.uint8)
green[imask] = optical_flow_arrows[imask]
# Here I need to calculate the variation of the optical flow
# Any ideas about how to do it?
cv.imshow("binarized", binary_flow)
cv.imshow("dense_optical_flow", optical_flow_arrows)
cv.imshow('color', green)
prev_gray = gray
if cv.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv.destroyAllWindows()