【图像处理】openCV光流法追踪运动物体

来源:互联网 发布:安卓登录源码 编辑:程序博客网 时间:2024/05/20 06:31

openCV光流法追踪运动物体

email:chentravelling@163.com

一、光流简介

摘自:zouxy09

        光流的概念是Gibson在1950年首先提出来的。它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。

研究光流场的目的就是为了从图片序列中近似得到不能直接得到的运动场。运动场,其实就是物体在三维真实世界中的运动;光流场,是运动场在二维图像平面上(人的眼睛或者摄像头)的投影。

       那通俗的讲就是通过一个图片序列,把每张图像中每个像素的运动速度和运动方向找出来就是光流场。那怎么找呢?咱们直观理解肯定是:第t帧的时候A点的位置是(x1, y1),那么我们在第t+1帧的时候再找到A点,假如它的位置是(x2,y2),那么我们就可以确定A点的运动了:(ux, vy) = (x2, y2) - (x1,y1)。

        那怎么知道第t+1帧的时候A点的位置呢? 这就存在很多的光流计算方法了。

       1981年,Horn和Schunck创造性地将二维速度场与灰度相联系,引入光流约束方程,得到光流计算的基本算法。人们基于不同的理论基础提出各种光流计算方法,算法性能各有不同。Barron等人对多种光流计算技术进行了总结,按照理论基础与数学方法的区别把它们分成四种:基于梯度的方法、基于匹配的方法、基于能量的方法、基于相位的方法。近年来神经动力学方法也颇受学者重视。

OpenCV中实现了不少的光流算法。

可参考:http://www.opencv.org.cn/opencvdoc/2.3.2/html/modules/video/doc/motion_analysis_and_object_tracking.html

1)calcOpticalFlowPyrLK

通过金字塔Lucas-Kanade 光流方法计算某些点集的光流(稀疏光流)。理解的话,可以参考这篇论文:”Pyramidal Implementation of the Lucas Kanade Feature TrackerDescription of the algorithm”

2)calcOpticalFlowFarneback

用Gunnar Farneback 的算法计算稠密光流(即图像上所有像素点的光流都计算出来)。它的相关论文是:"Two-Frame Motion Estimation Based on PolynomialExpansion"

3)CalcOpticalFlowBM

通过块匹配的方法来计算光流。

4)CalcOpticalFlowHS

用Horn-Schunck 的算法计算稠密光流。相关论文好像是这篇:”Determining Optical Flow”

5)calcOpticalFlowSF

这一个是2012年欧洲视觉会议的一篇文章的实现:"SimpleFlow: A Non-iterative, Sublinear Optical FlowAlgorithm",工程网站是:http://graphics.berkeley.edu/papers/Tao-SAN-2012-05/  在OpenCV新版本中有引入。

       稠密光流需要使用某种插值方法在比较容易跟踪的像素之间进行插值以解决那些运动不明确的像素,所以它的计算开销是相当大的。而对于稀疏光流来说,在他计算时需要在被跟踪之前指定一组点(容易跟踪的点,例如角点),因此在使用LK方法之前我们需要配合使用cvGoodFeatureToTrack()来寻找角点,然后利用金字塔LK光流算法,对运动进行跟踪。

二、代码

#include <opencv2\opencv.hpp>#include <iostream>using namespace std;using namespace cv;const int MAX_CORNERS = 100;int main(){IplImage* preImage = cvLoadImage("image133.pgm",CV_LOAD_IMAGE_GRAYSCALE);IplImage* curImage = cvLoadImage("image134.pgm",CV_LOAD_IMAGE_GRAYSCALE);IplImage* curImage_ = cvLoadImage("image134.pgm");CvPoint2D32f* preFeatures = new CvPoint2D32f[ MAX_CORNERS ];//前一帧中特征点坐标(通过cvGoodFeaturesToTrack获得)  CvPoint2D32f* curFeatures = new CvPoint2D32f[ MAX_CORNERS ];//在当前帧中的特征点坐标(通过光流法获得)double qlevel; //特征检测的指标  double minDist;//特征点之间最小容忍距离  vector<uchar> status; //特征点被成功跟踪的标志  vector<float> err; //跟踪时的特征点小区域误差和 CvSize      img_sz    = cvGetSize(preImage);  IplImage* eig_image = cvCreateImage( img_sz, IPL_DEPTH_32F, 1 );//缓冲区  IplImage* tmp_image = cvCreateImage( img_sz, IPL_DEPTH_32F, 1 );int num = MAX_CORNERS;cvGoodFeaturesToTrack(//获取特征点preImage,eig_image,tmp_image,preFeatures,&num,0.01,  5.0,  0,  3,  0,  0.04  );CvSize pyr_sz = cvSize( curImage->width+8, curImage->height/3 );  IplImage* pyrA = cvCreateImage( pyr_sz, IPL_DEPTH_32F, 1 );  IplImage* pyrB = cvCreateImage( pyr_sz, IPL_DEPTH_32F, 1 );  char features_found[ MAX_CORNERS ];  float feature_errors[ MAX_CORNERS ];  cvCalcOpticalFlowPyrLK(//计算光流preImage,curImage,pyrA,pyrB,preFeatures,curFeatures,MAX_CORNERS,cvSize(10,10),5,  features_found,  feature_errors,  cvTermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, .3 ),  0  );for(int i=0;i<MAX_CORNERS;i++)//画线{cvLine(curImage_,Point(preFeatures[i].x,preFeatures[i].y),Point(curFeatures[i].x,curFeatures[i].y),CV_RGB(255,0,0),4,CV_AA,0);}cvShowImage("outPutImage",curImage_);//cvSaveImage("outPutImage.pgm",curImage);waitKey(0);return 0;}

最终结果:



3 0