光流检测（optical flow）

函数中count参数，虽然是输出参数，表示特征点的数目，但是这个初值设置至关重要。设置为0时，代码运行会错误。设置为1时，没有特征点输出，一般设置为最大特征点数目。（原因不明白）

cvGoodFeaturesToTrack，http://blog.csdn.net/moc062066/article/details/6634120，

cvFindCornerSubPix，http://blog.csdn.net/moc062066/article/details/6634961

Calculates the optical flow for a sparse feature set using the iterative Lucas-Kanade method with
pyramids.

//通过Lucas-Kanade方法与图像金字塔的结合，计算稀疏特征集合的光流

1. <span style="font-size: 18px;">void cvCalcOpticalFlowPyrLK(
2.                             const CvArr* prev,
3.                             const CvArr* curr,
4.                             CvArr* prevPyr,
5.                             CvArr* currPyr,
6.                             const CvPoint2D32f* prevFeatures,
7.                             CvPoint2D32f* currFeatures,
8.                             int count,
9.                             CvSize winSize,
10.                             int level,
11.                             char* status,
12.                             float* track error,
13.                             CvTermCriteria criteria,
14.                             int flags );</span>
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

cvCalcOpticalFlowPyrLK函数中最后一个标志位，FLAG在视频处理中很重要。要提高速度，不重复计算金字塔，这里需要设置FLAG.即保存前一帧的金字塔数据和特征点，做为下一帧的初始帧。

1. //cvCaclOpticalFlowPyrLk_demo
2. //mochen
3. //2011年7月26日20:23:42
4.
5. #include <stdio.h>
6. #include "cv.h"
7. #include "cxcore.h"
8. #include "highgui.h"
9.
10. #pragma comment(lib, "opencv_core220d.lib")
11. #pragma comment(lib, "opencv_highgui220d.lib")
12. #pragma comment(lib, "opencv_imgproc220d.lib")
13. #pragma comment(lib, "opencv_calib3d220d.lib")
14. #pragma comment(lib, "opencv_features2d220d.lib")
15. #pragma comment(lib, "opencv_contrib220d.lib")
16. #pragma comment(lib, "opencv_ml220d.lib")
17. #pragma comment(lib, "opencv_video220d.lib")
18.
19.
20. #if 0
21. void cvCalcOpticalFlowPyrLK(
22.                             const CvArr* prev,
23.                             const CvArr* curr,
24.                             CvArr* prevPyr,
25.                             CvArr* currPyr,
26.                             const CvPoint2D32f* prevFeatures,
27.                             CvPoint2D32f* currFeatures,
28.                             int count,
29.                             CvSize winSize,
30.                             int level,
31.                             char* status,
32.                             float* track error,
33.                             CvTermCriteria criteria,
34.                             int flags );
35. #endif
36.
37. const int MAX_CORNERS = 1000 ;
38.
39. int main(int argc,char** argv)
40.     while ( 1 )
41.     {
42.         //use webcam
43.         CvCapture* cam = cvCaptureFromCAM( CV_CAP_ANY ) ;
44.         assert( NULL != cam ) ;
45.
46.         //get a color image
47.         IplImage* frame = cvQueryFrame(cam) ;
48.
49.         CvSize img_sz = cvGetSize(frame);
50.         const int win_size = 10 ;
51.
52.         //convert the image to grey image
53.         IplImage* frame_prev = cvQueryFrame(cam) ;
54.         IplImage* img_prev = cvCreateImage(img_sz,IPL_DEPTH_8U,1) ;
55.         cvCvtColor( frame_prev,img_prev ,CV_BGR2GRAY);
56.
57.         //convert the image to grey image
58.         IplImage* frame_cur = cvQueryFrame(cam) ;
59.         IplImage* img_curr = cvCreateImage(img_sz,IPL_DEPTH_8U,1) ;
60.         cvCvtColor( frame_cur,img_curr ,CV_BGR2GRAY);
61.
62.         //create a imge to display result
63.         IplImage* img_res = cvCreateImage(img_sz,IPL_DEPTH_8U,1) ;
64.         for ( int y = 0 ; y < img_sz.height ; ++y )
65.         {
66.             uchar* ptr = (uchar*)( img_res->imageData + y * img_res->widthStep ) ;
67.             for ( int x = 0 ; x <img_res->width; ++x )
68.             {
69.                 ptr[x] = 255 ;
70.             }
71.         }
72.
73.         //get good features
74.         IplImage* img_eig = cvCreateImage(img_sz,IPL_DEPTH_32F,1) ;
75.         IplImage* img_temp = cvCreateImage(img_sz,IPL_DEPTH_32F,1) ;
76.         int corner_count = MAX_CORNERS ;
77.         CvPoint2D32f*  features_prev = new CvPoint2D32f[MAX_CORNERS] ;
78.
79.         cvGoodFeaturesToTrack(
80.             img_prev,
81.             img_eig,
82.             img_temp,
83.             features_prev,
84.             &corner_count,
85.             0.01,
86.             5.0,
87.             0,
88.             3,
89.             0,
90.             0.4
91.             );
92.
93.         cvFindCornerSubPix(
94.             img_prev,
95.             features_prev,
96.             corner_count,
97.             cvSize(win_size,win_size),
98.             cvSize(-1,-1),
99.             cvTermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER,20,0.03)
100.             );
101.
102.         // L-K
103.         char feature_found[ MAX_CORNERS ] ;
104.         float feature_errors[ MAX_CORNERS ] ;
105.
106.         CvSize pyr_sz = cvSize( frame->width + 8 ,frame->height / 3 ) ;
107.
108.         IplImage* pyr_prev = cvCreateImage(img_sz,IPL_DEPTH_32F,1) ;
109.         IplImage* pyr_cur = cvCreateImage(img_sz,IPL_DEPTH_32F,1) ;
110.         CvPoint2D32f*  features_cur = new CvPoint2D32f[ MAX_CORNERS ] ;
111.
112.         cvCalcOpticalFlowPyrLK(
113.             img_prev,
114.             img_curr,
115.             pyr_prev,
116.             pyr_cur,
117.             features_prev,
118.             features_cur,
119.             corner_count,
120.             cvSize(win_size,win_size),
121.             5,
122.             feature_found,
123.             feature_errors,
124.             cvTermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER,20,0.3),
125.             0
126.             );
127.
128.         for ( int i = 0 ; i < corner_count ; i++)
129.         {
130.             if ( 0 == feature_found[i] || feature_errors[i] > 550 )
131.             {
132.                 printf("error is %f \n" , feature_errors[i] ) ;
133.                 continue
134.             }
135.
136.             printf("find it !\n") ;
137.
138.             CvPoint pt_prev = cvPoint( features_prev[i].x , features_prev[i].y ) ;
139.             CvPoint pt_cur = cvPoint( features_cur[i].x , features_cur[i].y ) ;
140.
141.             cvLine( img_res,pt_prev,pt_cur,CV_RGB( 255,0,0),2 );
142.         }
143.
144.         const char* window_prev ="img_prev"
145.         const char* window_curr ="img_curr"
146.         const char* window_res ="result"
147.         cvNamedWindow(window_prev,CV_WINDOW_AUTOSIZE);
148.         cvNamedWindow(window_curr,CV_WINDOW_AUTOSIZE);
149.         cvNamedWindow(window_res,CV_WINDOW_AUTOSIZE);
150.
151.         cvShowImage( window_prev,img_prev );
152.         cvShowImage( window_curr,img_curr );
153.         cvShowImage( window_res,img_res );
154.
155.         char opt = cvWaitKey( 10000 ) ;
156.         if ( 27 == opt )
157.         {
158.             break
159.         }
160.
161.         cvReleaseCapture( &cam );
162.         cvReleaseImage( &img_curr );
163.         cvReleaseImage( &img_eig );
164.         cvReleaseImage( &img_prev );
165.         cvReleaseImage( &img_res );
166.         cvReleaseImage( &img_temp );
167.         cvDestroyAllWindows() ;
168.     }
169.
170.
171.     return 0 ;

int CMotionOptic::OpticalFlow()

CvPoint2D32f *m_pPreConners1 = new CvPoint2D32f[MAX_CONNERS];
CvPoint2D32f *m_pCurConners1 = new CvPoint2D32f[MAX_CONNERS];

char aFeatureFound[MAX_CONNERS];
float aTrackErrors[MAX_CONNERS];

IplImage* m_pPyrCurImg1 = cvCreateImage(cvSize(m_iWidth,m_iHeight), IPL_DEPTH_32F,1);
IplImage *m_pPyrPreImg1 = cvCreateImage(cvSize(m_iWidth,m_iHeight), IPL_DEPTH_32F,1);

//int m_iConnersCnt1 = MAX_CONNERS;

if(1 == m_iStartFrameCnt)
{

cvGoodFeaturesToTrack(m_pPreImg,m_pEigImg,m_pTmpImg,m_pPreConners,&m_iConnersCnt,0.01,5.0,0,3,0,0.04);

cvFindCornerSubPix(m_pPreImg,m_pPreConners,m_iConnersCnt,cvSize(10,10),cvSize(-1,-1),
cvTermCriteria(CV_TERMCRIT_EPS|CV_TERMCRIT_ITER, 200,0.03));

cvCalcOpticalFlowPyrLK(m_pPreImg, m_pCurImg, m_pPyrPreImg, m_pPyrCurImg, m_pPreConners,
m_pCurConners,m_iConnersCnt,cvSize(10,10),5,aFeatureFound,aTrackErrors,
cvTermCriteria(CV_TERMCRIT_EPS|CV_TERMCRIT_ITER, 200, 0.03),0);
}
else
{
cvCalcOpticalFlowPyrLK(m_pPreImg, m_pCurImg, m_pPyrPreImg, m_pPyrCurImg, m_pPreConners,
m_pCurConners,m_iConnersCnt,cvSize(10,10),5,aFeatureFound,aTrackErrors,
}

for(int iLoop = 0;iLoop < m_iConnersCnt; iLoop++)
{
if((0 == aFeatureFound[iLoop])||(aTrackErrors[iLoop] > 550))
{
printf("Error is %f",aTrackErrors[iLoop]);
continue;
}

CvPoint pt0 = cvPoint(cvRound(m_pPreConners[iLoop].x), cvRound(m_pPreConners[iLoop].y));
CvPoint pt1 = cvPoint(cvRound(m_pCurConners[iLoop].x), cvRound(m_pCurConners[iLoop].y));

if((abs(pt0.x - pt1.x) >= 1)||(abs(pt0.y - pt1.y) >= 1))
{
cvLine(m_pCurImg,pt0,pt1,cvScalar(255,0,0),2);
cvLine(m_pPreImg,pt0,pt1,cvScalar(255,0,0),2);
}
}

cvShowImage("PreOptica", m_pPreImg);
cvShowImage("CurOptica", m_pCurImg);

memcpy(m_pPyrPreImg->imageData, m_pPyrCurImg->imageData, (m_iWidth+8)*(m_iHeight/3)*4);
memcpy(m_pPreConners, m_pCurConners, m_iConnersCnt*sizeof(CvPoint2D32f));

return 0;
}