光流检测(optical flow)

本文详细介绍了视频处理中的关键步骤,包括使用OpenCV库进行图像预处理、特征点检测、金字塔构建以及光流计算。重点阐述了cvCalcOpticalFlowPyrLK函数的应用,解释了参数设置的重要性,特别是count参数的正确初始化。此外,文章还讨论了如何通过设置FLAG提高处理速度并减少重复计算,从而优化视频处理流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

 

cvGoodFeaturesToTrack,http://blog.youkuaiyun.com/moc062066/article/details/6634120,

cvFindCornerSubPix,http://blog.youkuaiyun.com/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方法与图像金字塔的结合,计算稀疏特征集合的光流

  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 ; 

 

下面一段代码为视频处理,设置FLAG

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,
   cvTermCriteria(CV_TERMCRIT_EPS|CV_TERMCRIT_ITER, 200, 0.03),CV_LKFLOW_PYR_A_READY);  
 } 

 
 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;
}

 

 

 

### 回答1: bounding box是指在图像中定位物体或区域的矩形框。而是指描述图像中像素在不同时间或帧之间的运动向量。 将bounding box作为optical flow输入可以通过以下步骤实现: 首先,根据任务的需求,在图像中选择目标物体或区域,并用bounding box进行标注。 然后,利用计算机视觉算法,例如基于深度学习的目标检测算法,对图像中的目标进行检测和定位。该算法将输入图像和bounding box作为输入,并输出目标检测结果。 接下来,对于每一帧图像中的bounding box,利用算法计算目标区域的运动向量。算法能够分析相邻帧之间的像素变化,并计算出物体在图像中的运动情况。 最后,根据算法计算出的运动向量,可以进一步分析目标物体的运动轨迹、速度和加速度等运动信息。这些信息可以应用于许多计算机视觉任务,例如运动跟踪、行为分析和视频压缩等。 通过将bounding box作为optical flow输入,可以更加准确地分析目标物体的运动情况,并为后续的任务提供更丰富的信息。这种方法在许多视觉任务中具有广泛的应用,例如视频监控、自动驾驶和虚拟现实等领域。 ### 回答2: bounding box(边界框)在计算机视觉领域中常用于表示物体在图像中的位置和范围。而optical flow)是一种用于估计图像中像素运动的技术。 将bounding box作为optical flow的输入意味着我们希望通过来估计给定物体在图像中的运动。通过监测bounding box的运动,我们可以了解物体的位移、速度和方向等运动信息。 在这种方法中,首先需要使用目标检测算法或手工标注的方式得到bounding box的位置。然后,我们可以使用算法对bounding box中的像素进行跟踪和分析,以获取物体的运动信息。 使用bounding box作为optical flow输入的好处是,只需对感兴趣的区域进行计算,减少了计算量,提高了计算效率。而且,通过对物体运动的分析,我们可以获得更精确的物体运动信息,有助于在视觉跟踪和行为分析等领域中的应用。 然而,bounding box作为optical flow输入也存在一些挑战和限制。首先,bounding box的准确性对的计算结果有很大的影响,如果bounding box的位置不准确,可能会导致计算出的运动结果不准确。此外,如果物体发生较大的旋转、遮挡或形变等情况,bounding box的边界可能无法完整地包围物体,从而影响的计算和分析结果。 综上所述,bounding box作为optical flow的输入可以用来估计给定物体在图像中的运动。但在使用时需要注意bounding box的准确性和在特定情况下的局限性。 ### 回答3: bounding box作为optical flow的输入,是指在目标跟踪或目标检测任务中,使用bounding box来框定目标区域,并将该区域作为输入,进行计算。 是一种用于分析图像中像素运动的技术。它能够通过比较相邻帧中的像素位置变化,推测像素的运动方向和速度。为了准确地计算,需要选择合适的输入区域。而bounding box提供了一个有效的方式来定义并限制计算的区域,以便准确地追踪目标的运动。 具体而言,使用bounding box作为的输入可以带来以下优势: 1. 限定区域:bounding box可以将计算限定在目标区域内,从而排除其他背景区域的干扰。这样可以提高的计算精度和效率。 2. 快速目标跟踪:可以用于目标跟踪任务,而bounding box提供了目标的初始位置信息。通过计算,可以根据目标的运动轨迹对目标进行跟踪,并及时更新bounding box的位置。 3. 目标检测准确性:可以用于目标检测任务,通过计算不同帧之间的变化,可以检测出目标的运动。而bounding box则可以用来获取目标在当前帧中的位置,从而进一步提高目标检测的准确性。 总之,使用bounding box作为optical flow的输入,可以更好地限定计算的区域,提高的计算精度和效率,同时也可以用于目标跟踪和目标检测任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值