检测视频中光流的高变化

时间:2019-05-10 03:42:01

标签: python opencv computer-vision video-processing acceleration

我需要检测视频中光流的高度变化。例如,十字路口。两辆汽车在行驶,它们具有一定的光通量值。接下来,在一定时间段内,它们会发生碰撞,因此会产生较大的光流变化。如何检测?

具有二值化和遮罩的光学流

optical flow with binarization and mask

当光流的变化较大时,期望着火结果

expecting the result to fire event when the variation of the optical flow high

如何捕获此事件?

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()

0 个答案:

没有答案