函数解析
cvGoodFeaturesToTrack,http://blog.csdn.net/moc062066/article/details/6634120,和
cvFindCornerSubPix ,http://blog.csdn.net/moc062066/article/details/6634961
两个函数的基础,接下来就是在视频中检测光流(optical flow),经常用的函数是cvCalcOpticalFlowPyrLK,函数说明如下;
Calculates the optical flow for a sparse feature set using the iterative Lucas-Kanade method with
pyramids.
//通过Lucas-Kanade方法与图像金字塔的结合,计算稀疏特征集合的光流
void cvCalcOpticalFlowPyrLK(
const CvArr* prev,
const CvArr* curr,
CvArr* prevPyr,
CvArr* currPyr,
const CvPoint2D32f* prevFeatures,
CvPoint2D32f* currFeatures,
int count,
CvSize winSize,
int level,
char* status,
float* track error,
CvTermCriteria criteria,
int flags );
prev First frame, at time t //取t时刻为第一帧
curr Second frame, at time t + dt //第二帧出现在 t + dt时刻
prevPyr Buffer for the pyramid for the first frame. If the pointer is not NULL , the buffer must
have a sufficient size to store the pyramid from level 1 to level level ; the total size of
(image width+8)*image height/3 bytes is sufficient
//第一帧的图像金字塔的缓存之处。如果该指针不为空,该buffer必须有足够的空间来存储从第1层到第level 层的图像金字塔;prevPyr 指针所指的图像/矩阵的大小为(image width+8) * (image height/3) 就足够了。
currPyr Similar to prevPyr, used for the second frame //同上
prevFeatures Array of points for which the flow needs to be found //在数组中定义(当前帧中的)那些点是要在(下一帧)检测的
currFeatures Array of 2D points containing the calculated new positions of the input features
in the second image
//一个二维的点数组,用于存放输入的特征(就是prevFeatures )在第二帧中的新位置
count Number of feature points//特征点的数目
winSize Size of the search window of each pyramid level //每一层金字塔所有的搜索窗口的大小
level Maximal pyramid level number. If 0 , pyramids are not used (single level), if 1 , two levels
are used, etc
//最多有多少层金字塔。如果是0,就不用图像金字塔,如果是1,就有两层,以此类推。
status Array. Every element of the array is set to 1 if the flow for the corresponding feature has
been found, 0 otherwise
//是一个数组,对应点在第二帧中找到,那该位置就值为1,找不到就值为0.
track error Array of double numbers containing the difference between patches around the
original and moved points. Optional parameter; can be NULL
criteria Specifies when the iteration process of finding the flow for each point on each pyramid
level should be stopped
flags Miscellaneous flags:
CV LKFLOWPyr A READY pyramid for the first frame is precalculated before the call
CV LKFLOWPyr B READY pyramid for the second frame is precalculated before the call
CV LKFLOW INITIAL GUESSES array B contains initial coordinates of features before the
function call
demo:
//cvCaclOpticalFlowPyrLk_demo //mochen //2011年7月26日20:23:42 #include <stdio.h> #include "cv.h" #include "cxcore.h" #include "highgui.h" #pragma comment(lib, "opencv_core220d.lib") #pragma comment(lib, "opencv_highgui220d.lib") #pragma comment(lib, "opencv_imgproc220d.lib") #pragma comment(lib, "opencv_calib3d220d.lib") #pragma comment(lib, "opencv_features2d220d.lib") #pragma comment(lib, "opencv_contrib220d.lib") #pragma comment(lib, "opencv_ml220d.lib") #pragma comment(lib, "opencv_video220d.lib") #if 0 void cvCalcOpticalFlowPyrLK( const CvArr* prev, const CvArr* curr, CvArr* prevPyr, CvArr* currPyr, const CvPoint2D32f* prevFeatures, CvPoint2D32f* currFeatures, int count, CvSize winSize, int level, char* status, float* track error, CvTermCriteria criteria, int flags ); #endif const int MAX_CORNERS = 1000 ; int main(int argc,char** argv) { while ( 1 ) { //use webcam CvCapture* cam = cvCaptureFromCAM( CV_CAP_ANY ) ; assert( NULL != cam ) ; //get a color image IplImage* frame = cvQueryFrame(cam) ; CvSize img_sz = cvGetSize(frame); const int win_size = 10 ; //convert the image to grey image IplImage* frame_prev = cvQueryFrame(cam) ; IplImage* img_prev = cvCreateImage(img_sz,IPL_DEPTH_8U,1) ; cvCvtColor( frame_prev,img_prev ,CV_BGR2GRAY); //convert the image to grey image IplImage* frame_cur = cvQueryFrame(cam) ; IplImage* img_curr = cvCreateImage(img_sz,IPL_DEPTH_8U,1) ; cvCvtColor( frame_cur,img_curr ,CV_BGR2GRAY); //create a imge to display result IplImage* img_res = cvCreateImage(img_sz,IPL_DEPTH_8U,1) ; for ( int y = 0 ; y < img_sz.height ; ++y ) { uchar* ptr = (uchar*)( img_res->imageData + y * img_res->widthStep ) ; for ( int x = 0 ; x <img_res->width; ++x ) { ptr[x] = 255 ; } } //get good features IplImage* img_eig = cvCreateImage(img_sz,IPL_DEPTH_32F,1) ; IplImage* img_temp = cvCreateImage(img_sz,IPL_DEPTH_32F,1) ; int corner_count = MAX_CORNERS ; CvPoint2D32f* features_prev = new CvPoint2D32f[MAX_CORNERS] ; cvGoodFeaturesToTrack( img_prev, img_eig, img_temp, features_prev, &corner_count, 0.01, 5.0, 0, 3, 0, 0.4 ); cvFindCornerSubPix( img_prev, features_prev, corner_count, cvSize(win_size,win_size), cvSize(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER,20,0.03) ); // L-K char feature_found[ MAX_CORNERS ] ; float feature_errors[ MAX_CORNERS ] ; CvSize pyr_sz = cvSize( frame->width + 8 ,frame->height / 3 ) ; IplImage* pyr_prev = cvCreateImage(img_sz,IPL_DEPTH_32F,1) ; IplImage* pyr_cur = cvCreateImage(img_sz,IPL_DEPTH_32F,1) ; CvPoint2D32f* features_cur = new CvPoint2D32f[ MAX_CORNERS ] ; cvCalcOpticalFlowPyrLK( img_prev, img_curr, pyr_prev, pyr_cur, features_prev, features_cur, corner_count, cvSize(win_size,win_size), 5, feature_found, feature_errors, cvTermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER,20,0.3), 0 ); for ( int i = 0 ; i < corner_count ; i++) { if ( 0 == feature_found[i] || feature_errors[i] > 550 ) { printf("error is %f \n" , feature_errors[i] ) ; continue ; } printf("find it !\n") ; CvPoint pt_prev = cvPoint( features_prev[i].x , features_prev[i].y ) ; CvPoint pt_cur = cvPoint( features_cur[i].x , features_cur[i].y ) ; cvLine( img_res,pt_prev,pt_cur,CV_RGB( 255,0,0),2 ); } const char* window_prev = "img_prev" ; const char* window_curr = "img_curr" ; const char* window_res = "result" ; cvNamedWindow(window_prev,CV_WINDOW_AUTOSIZE); cvNamedWindow(window_curr,CV_WINDOW_AUTOSIZE); cvNamedWindow(window_res,CV_WINDOW_AUTOSIZE); cvShowImage( window_prev,img_prev ); cvShowImage( window_curr,img_curr ); cvShowImage( window_res,img_res ); char opt = cvWaitKey( 10000 ) ; if ( 27 == opt ) { break ; } cvReleaseCapture( &cam ); cvReleaseImage( &img_curr ); cvReleaseImage( &img_eig ); cvReleaseImage( &img_prev ); cvReleaseImage( &img_res ); cvReleaseImage( &img_temp ); cvDestroyAllWindows() ; } return 0 ; }