函數解析
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 ;
}
結果: