To find optical flow as ndarray using cv2.calcOpticalFlowPyrLK()

丶灬走出姿态 提交于 2020-04-18 06:13:53

问题


I need to find the optical flow between every 2 adjacent frames of a video using Lucas Kanade optical flow. I'm using python and openCV for the project.

As per my understanding Lucas Kanade is a sparse method to find optical flow. Is there a dense implementation of it? If so, how to use it in python?

Using cv2.calcOpticalFlowFarneback(), which is a dense method, we get as output an ndarray ('flow' in below example) which contains the optical flow.

cv2.calcOpticalFlowFarneback(prev, next, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags[, flow]) → flow

Is there a way to get a similar output using cv2.calcOpticalFlowPyrLK()?

cv2.calcOpticalFlowPyrLK(prevImg, nextImg, prevPts[, nextPts[, status[, err[, winSize[, maxLevel[, criteria[, flags[, minEigThreshold]]]]]]]]) → nextPts, status, err

When using cv2.calcOpticalFlowPyrLK() (above), the output obtained contains nextPts which contains the next points to track but it does not directly give optical flow of the 2 frames. If I subtract the prevPts from nextPts, is the result the optical flow between the two frames? I found ' prev(y,x)~next(y+flow(y,x)[1],x+flow(y,x)[0]) ' in the section explaining calcOpticalFlowFarneback() in this link: https://docs.opencv.org/2.4/modules/video/doc/motion_analysis_and_object_tracking.html hence the question. (The syntax for both cv2.calcOpticalFlowPyrLK() and cv2.calcOpticalFlowFarneback are also from this link) Below is my implementation of the same.

import cv2
import numpy as np
import os
import subprocess as sp

yuv_filename = 'can_0.yuv'
flow=[]

width, height = 320, 240

file_size = os.path.getsize(yuv_filename)
n_frames = file_size // (width*height*3 // 2)
f = open(yuv_filename, 'rb')


old_yuv = np.frombuffer(f.read(width*height*3//2), dtype=np.uint8).reshape((height*3//2, width))


# Convert YUV420 to Grayscale
old_gray = cv2.cvtColor(old_yuv, cv2.COLOR_YUV2GRAY_I420)


# params for ShiTomasi corner detection
feature_params = dict( maxCorners = 100,
                       qualityLevel = 0.3,
                       minDistance = 7,
                       blockSize = 7 )

# Parameters for lucas kanade optical flow
lk_params = dict( winSize  = (15,15),
                  maxLevel = 2,
                  criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))


p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)


for i in range(1,n_frames):
    # Read Y, U and V color channels and reshape to height*1.5 x width numpy array
    yuv = np.frombuffer(f.read(width*height*3//2), dtype=np.uint8).reshape((height*3//2, width))

    # Convert YUV420 to Grayscale
    gray = cv2.cvtColor(yuv, cv2.COLOR_YUV2GRAY_I420)

    # calculate optical flow
    p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, gray, p0, None, **lk_params)


    flow.append(np.subtract(p1,p0))
    good_old = p0[st==1]
    good_new = p1[st==1]


    # Now update the previous frame and previous points
    old_gray = gray.copy()
    p0 = good_new.reshape(-1,1,2)


f.close()

Is flow a list of ndarrays containing the optical flow between adjacent frames of the input video?

This is the output I got for flow[7] (randomly selected) but I'm not sure if it is optical flow values.

[[[ 6.7138672e-03 4.5318604e-03]]

[[-1.6220093e-02 1.9645691e-03]]

[[-8.5296631e-03 1.8482208e-03]]

[[-5.8441162e-03 1.5701294e-02]]

[[ 7.5836182e-03 2.3475647e-02]]

[[-1.4129639e-02 1.6357422e-02]]

[[ 4.4555664e-03 4.1809082e-03]]

[[ 5.6457520e-04 -9.5863342e-03]]

[[ 2.8991699e-04 -3.0517578e-05]]

[[-2.3452759e-02 -1.5502930e-02]]

[[-6.8283081e-03 3.3264160e-03]]

[[-8.4381104e-03 7.7590942e-03]]

[[ 5.7144165e-03 1.1177063e-02]]

[[-1.4160156e-02 2.1179199e-02]]

[[-1.0498047e-02 8.0099106e-03]]

[[-1.8310547e-04 2.8953552e-03]]

[[ 4.4937134e-03 -2.0904541e-03]]

[[-4.7698975e-02 3.7708282e-02]]

[[ 6.3323975e-03 1.3298035e-02]]

[[-3.3233643e-02 -1.7229080e-02]]

[[ 7.5683594e-03 2.4566650e-03]]

[[-3.0364990e-03 3.4656525e-03]]

[[-1.0345459e-02 -7.4539185e-03]]

[[ 1.3168335e-02 2.1423340e-02]]

[[-6.3476562e-03 -1.0681152e-02]]

[[ 1.5869141e-03 1.0375977e-03]]

[[ 2.1820068e-03 6.7329407e-03]]

[[-9.6130371e-03 2.9449463e-03]]

[[-2.1362305e-03 8.5525513e-03]]

[[-1.7547607e-04 2.1362305e-04]]

[[ 2.9144287e-03 1.4343262e-03]]

[[ 2.9602051e-03 -7.1868896e-03]]

[[-1.2878418e-02 5.0182343e-03]]

[[-3.1585693e-03 -5.0544739e-05]]

[[ 1.0070801e-03 1.3740540e-02]]

[[ 6.7138672e-04 1.7852783e-03]]

[[-2.0568848e-02 -1.2943268e-02]]

[[-2.1057129e-03 4.5013428e-03]]]

Also is there a way to get optical flow using Lucas Kanade method such that it has the same size or dimensions as the input frames? If so how?


回答1:


You can estimate a dense flow field with the pure pyramidal Lucas Kanade method by computing for each pixel the corresponding point pairs. To do that:

  • ignore cv2.goodFeaturesToTrack
  • initialize point list p0 that contains all pixel locations of the image
  • assemble dense flow field by computing and reshape motion vectors list computed by mv=p1-p0

However, this is not the most efficient way to compute a dense optical flow field. In OpenCV you may take a look to other DenseOpticalFlow methods (e.g. DIS, Farneback, RLOFDense, Dual-TVL1)



来源:https://stackoverflow.com/questions/61035461/to-find-optical-flow-as-ndarray-using-cv2-calcopticalflowpyrlk

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!