Python-OpenCV 处理视频(三): 标记运动轨迹

0x00. 光流

光流是进行视频中运动对象轨迹标记的一种很常用的方法,在OpenCV中实现光流也很容易。

CalcOpticalFlowPyrLK 函数计算一个稀疏特征集的光流,使用金字塔中的迭代 Lucas-Kanade 方法。

简单的实现流程:

  1. 加载一段视频。
  2. 调用GoodFeaturesToTrack函数寻找兴趣点。
  3. 调用CalcOpticalFlowPyrLK函数计算出两帧图像中兴趣点的移动情况。
  4. 删除未移动的兴趣点。
  5. 在两次移动的点之间绘制一条线段。

代码示例:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 import cv2.cv as cv capture = cv.CaptureFromFile(\’img/myvideo.avi\’) nbFrames = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_COUNT))fps = cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FPS)wait = int(1/fps * 1000/1)width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH))height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT)) prev_gray = cv.CreateImage((width,height), 8, 1) #Will hold the frame at t-1gray = cv.CreateImage((width,height), 8, 1) # Will hold the current frame prevPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) #Will hold the pyr frame at t-1currPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) # idem at t max_count = 500qLevel= 0.01minDist = 10prev_points = [] #Points at t-1curr_points = [] #Points at tlines=[] #To keep all the lines overtime for f in xrange( nbFrames ):     frame = cv.QueryFrame(capture) #Take a frame of the video     cv.CvtColor(frame, gray, cv.CV_BGR2GRAY) #Convert to gray    output = cv.CloneImage(frame)     prev_points = cv.GoodFeaturesToTrack(gray, None, None, max_count, qLevel, minDist) #Find points on the image     #Calculate the movement using the previous and the current frame using the previous points    curr_points, status, err = cv.CalcOpticalFlowPyrLK(prev_gray, gray, prevPyr, currPyr, prev_points, (10, 10), 3, (cv.CV_TERMCRIT_ITER|cv.CV_TERMCRIT_EPS,20, 0.03), 0)      #If points status are ok and distance not negligible keep the point    k = 0    for i in range(len(curr_points)):        nb =  abs( int(prev_points[i][0])int(curr_points[i][0]) ) + abs( int(prev_points[i][1])int(curr_points[i][1]) )        if status[i] and  nb > 2 :            prev_points[k] = prev_points[i]            curr_points[k] = curr_points[i]            k += 1     prev_points = n class=\”crayon-o\”>+= 1     prev_points = li>加载一段视频。

  • 调用GoodFeaturesToTrack函数寻找兴趣点。
  • 调用CalcOpticalFlowPyrLK函数计算出两帧图像中兴趣点的移动情况。
  • 删除未移动的兴趣点。
  • 在两次移动的点之间绘制一条线段。
  • 代码示例:

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 import cv2.cv as cv capture = cv.CaptureFromFile(\’img/myvideo.avi\’) nbFrames = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_COUNT))fps = cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FPS)wait = int(1/fps * 1000/1)width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH))height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT)) prev_gray = cv.CreateImage((width,height), 8, 1) #Will hold the frame at t-1gray = cv.CreateImage((width,height), 8, 1) # Will hold the current frame prevPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) #Will hold the pyr frame at t-1currPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) # idem at t max_count = 500qLevel= 0.01minDist = 10prev_points = [] #Points at t-1curr_points = [] #Points at tlines=[] #To keep all the lines overtime for f in xrange( nbFrames ):     frame = cv.QueryFrame(capture) #Take a frame of the video     cv.CvtColor(frame, gray, cv.CV_BGR2GRAY) #Convert to gray    output = cv.CloneImage(frame)     prev_points = cv.GoodFeaturesToTrack(gray, None, None, max_count, qLevel, minDist) #Find points on the image     #Calculate the movement using the previous and the current frame using the previous points    curr_points, status, err = cv.CalcOpticalFlowPyrLK(prev_gray, gray, prevPyr, currPyr, prev_points, (10, 10), 3, (cv.CV_TERMCRIT_ITER|cv.CV_TERMCRIT_EPS,20, 0.03), 0)      #If points status are ok and distance not negligible keep the point    k = 0    for i in range(len(curr_points)):        nb =  abs( int(prev_points[i][0])int(curr_points[i][0]) ) + abs( int(prev_points[i][1])int(curr_points[i][1]) )        if status[i] and  nb > 2 :            prev_points[k] = prev_points[i]            curr_points[k] = curr_points[i]            k += 1