Opencv Python版学习笔记(五)光流跟踪 Lucas-Kanade(LK)算法

Lucas-Kanade算法最初也是计算稠密光流的,后来成为求稀疏光流的一种重要方法,这里要介绍的是金字塔LK算法:

在Python函数原型为:nextPts, status, err = calcOpticalFlowPyrLK(prevImg, nextImg, prevPts[, nextPts[, status[, err[, winSize[, maxLevel[, criteria[, flags[, minEigThreshold]]]]]]]])

参数说明:prevImage 前一帧8-bit图像

                  nextImage 当前帧8-bit图像

                  prevPts 待跟踪的特征点向量

                  nextPts 输出跟踪特征点向量

                  status 特征点是否找到,找到的状态为1,未找到的状态为0

                  err 输出错误向量,(不太理解用途...)

                  winSize 搜索窗口的大小

                  maxLevel 最大的金字塔层数

                  flags 可选标识:OPTFLOW_USE_INITIAL_FLOW   OPTFLOW_LK_GET_MIN_EIGENVALS

具体英文说明参照:http://docs.opencv.org/modules/video/doc/motion_analysis_and_object_tracking.html#cv2.calcOpticalFlowPyrLK

计算光流前需要先初始特征点,Python实例采用的是角点

函数原型:corners = cv2.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance[, corners[, mask[, blockSize[, useHarrisDetector[, k]]]]])

参数说明:image 输入的单通道图像,可以为8-bit或32-bit

                  maxCorners 最大的角点数,如果检测出的角点多余最大角点数,将取出最强最大角点数个角点

                  qualityLevel 最小可接受的角点质量

                  minDistance 角点间的最小欧几里得距离(也就是两个角点间不能太近)

                  corners 输出的检测到的角点

                  mask 需要检测角点的区域

                  blocksize 计算离散卷积块的大小

                  useHarrisDetector 是否使用Harris角点

代码及注释说明如下:

 

[python] view plain copy
  1. #encoding:utf-8  
  2. ''''' 
  3. Lucas-Kanade tracker 
  4. ==================== 
  5.  
  6. Lucas-Kanade sparse optical flow demo. Uses goodFeaturesToTrack 
  7. for track initialization and back-tracking for match verification 
  8. between frames. 
  9.  
  10. Usage 
  11. ----- 
  12. lk_track.py [] 
  13.  
  14.  
  15. Keys 
  16. ---- 
  17. ESC - exit 
  18. '''  
  19.   
  20. import numpy as np  
  21. import cv2  
  22. #from common import anorm2, draw_str  
  23. from time import clock  
  24.   
  25. lk_params = dict( winSize  = (1515),   
  26.                   maxLevel = 2,   
  27.                   criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 100.03))      
  28.   
  29. feature_params = dict( maxCorners = 500,   
  30.                        qualityLevel = 0.3,  
  31.                        minDistance = 7,  
  32.                        blockSize = 7 )  
  33.   
  34. class App:  
  35.     def __init__(self, video_src):#构造方法,初始化一些参数和视频路径  
  36.         self.track_len = 10  
  37.         self.detect_interval = 5  
  38.         self.tracks = []  
  39.         self.cam = cv2.VideoCapture(video_src)  
  40.         self.frame_idx = 0  
  41.   
  42.     def run(self):#光流运行方法  
  43.         while True:  
  44.             ret, frame = self.cam.read()#读取视频帧  
  45.             if ret == True:  
  46.                 frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)#转化为灰度虚图像  
  47.                 vis = frame.copy()  
  48.       
  49.                 if len(self.tracks) > 0:#检测到角点后进行光流跟踪  
  50.                     img0, img1 = self.prev_gray, frame_gray  
  51.                     p0 = np.float32([tr[-1for tr in self.tracks]).reshape(-112)  
  52.                     p1, st, err = cv2.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)#前一帧的角点和当前帧的图像作为输入来得到角点在当前帧的位置  
  53.                     p0r, st, err = cv2.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params)#当前帧跟踪到的角点及图像和前一帧的图像作为输入来找到前一帧的角点位置  
  54.                     d = abs(p0-p0r).reshape(-12).max(-1)#得到角点回溯与前一帧实际角点的位置变化关系  
  55.                     good = d < 1#判断d内的值是否小于1,大于1跟踪被认为是错误的跟踪点  
  56.                     new_tracks = []  
  57.                     for tr, (x, y), good_flag in zip(self.tracks, p1.reshape(-12), good):#将跟踪正确的点列入成功跟踪点  
  58.                         if not good_flag:  
  59.                             continue  
  60.                         tr.append((x, y))  
  61.                         if len(tr) > self.track_len:  
  62.                             del tr[0]  
  63.                         new_tracks.append(tr)  
  64.                         cv2.circle(vis, (x, y), 2, (02550), -1)  
  65.                     self.tracks = new_tracks  
  66.                     cv2.polylines(vis, [np.int32(tr) for tr in self.tracks], False, (02550))#以上一振角点为初始点,当前帧跟踪到的点为终点划线  
  67.                     #draw_str(vis, (20, 20), 'track count: %d' % len(self.tracks))  
  68.       
  69.                 if self.frame_idx % self.detect_interval == 0:#每5帧检测一次特征点  
  70.                     mask = np.zeros_like(frame_gray)#初始化和视频大小相同的图像  
  71.                     mask[:] = 255#将mask赋值255也就是算全部图像的角点  
  72.                     for x, y in [np.int32(tr[-1]) for tr in self.tracks]:#跟踪的角点画圆  
  73.                         cv2.circle(mask, (x, y), 50, -1)  
  74.                     p = cv2.goodFeaturesToTrack(frame_gray, mask = mask, **feature_params)#像素级别角点检测  
  75.                     if p is not None:  
  76.                         for x, y in np.float32(p).reshape(-12):  
  77.                             self.tracks.append([(x, y)])#将检测到的角点放在待跟踪序列中  
  78.       
  79.       
  80.                 self.frame_idx += 1  
  81.                 self.prev_gray = frame_gray  
  82.                 cv2.imshow('lk_track', vis)  
  83.   
  84.             ch = 0xFF & cv2.waitKey(1)  
  85.             if ch == 27:  
  86.                 break  
  87.   
  88. def main():  
  89.     import sys  
  90.     try: video_src = sys.argv[1]  
  91.     except: video_src = "E:\Megamind.avi"  
  92.   
  93.     print __doc__  
  94.     App(video_src).run()  
  95.     cv2.destroyAllWindows()               
  96.   
  97. if __name__ == '__main__':  
  98.     main()  

其中加入了对视频读取结束的判断 if ret == True:

效果图如下:

你可能感兴趣的:(opencv)