2015-10-26 75 views
4

我一直在试图实现跟踪对象的meanshift算法,并已经通过涉及的概念。Meanshift算法跟踪对象问题计算质心更新搜索窗口

按照现在我已经成功地从我的相机成功生成一个单通道色相roi直方图和一个单通道色调视频流,似乎很好,我知道opencv库中有一个meanshift函数,但我我试图使用opencv中提供的数据结构自己实现一个,计算矩和计算搜索窗口的平均质心。

但由于某种原因,我无法在代码中找到问题,因为它会一直收敛到视频流的左上角,以便跟踪任何输入roi(感兴趣区域)。以下是该函数的计算搜索窗口,我觉得这个问题的重心的代码片段谎言,但不知道它是什么,我会很感激,如果有人可以点我在正确的方向:

void moment(Mat &backproj, Rect &win){ 

    int x_c, y_c, x_c_new, y_c_new;  
    int idx_row, idx_col; 
    double m00 = 0.0 , m01 = 0.0 , m10 = 0.0 ; 
    double res = 1.0, TOL = 0.003 ; 

    //Set the center of search window as the center of the probabilistic image: 
    y_c = (int) backproj.rows/2 ; 
    x_c = (int) backproj.cols/2 ; 

    //Centroid search solver until residual below certain tolerance: 
    while (res > TOL){ 

     win.width = (int) 80; 
     win.height = (int) 60; 

     //First array element at position (x,y) "lower left corner" of the search window: 
     win.x = (int) (x_c - win.width/2) ; 
     win.y = (int) (y_c - win.height/2); 

     //Modulo correction since modulo of negative integer is negative in C: 
     if (win.x < 0) 
       win.x = win.x % backproj.cols + backproj.cols ; 

     if (win.y < 0) 
       win.y = win.y % backproj.rows + backproj.rows ; 

     for (int i = 0; i < win.height; i++){ 

       //Traverse along y-axis (height) i.e. rows ensuring wrap around top/bottom boundaries:     
       idx_row = (win.y + i) % (int)backproj.rows ; 

       for (int j = 0; j < win.width; j++){ 

         //Traverse along x-axis (width) i.e. cols ensuring wrap around left/right boundaries: 
         idx_col = (win.x + j) % (int)backproj.cols ;  
         //Compute Moments:        
         m00 += (double) backproj.at<uchar>(idx_row, idx_col) ; 
         m10 += (double) backproj.at<uchar>(idx_row, idx_col) * i ; 
         m01 += (double) backproj.at<uchar>(idx_row, idx_col) * j ; 
       } 
     } 

     //Compute new centroid coordinates of the search window: 
     x_c_new = (int) (m10/m00) ; 
     y_c_new = (int) (m01/m00); 

     //Compute the residual: 
     res = sqrt(pow((x_c_new - x_c), 2.0) + pow((y_c_new - y_c), 2.0)) ; 

     //Set new search window centroid coordinates: 
     x_c = x_c_new; 
     y_c = y_c_new; 
    } 
} 

这是我第二次在stackoverflow上查询,所以请原谅我忘记遵循的任何指南。

编辑

改变M00,M01,M10阻止WHILE-LOOP内级别变量代替功能级别的变量,由于丹尼尔Strul指点出来,但问题仍然存在。现在搜索窗口围绕框架边界跳跃,而不是关注roi。

void moment(Mat &backproj, Rect &win){ 

    int x_c, y_c, x_c_new, y_c_new;  
    int idx_row, idx_col; 
    double m00 , m01 , m10 ; 
    double res = 1.0, TOL = 0.003 ; 

    //Set the center of search window as the center of the probabilistic image: 
    y_c = (int) backproj.rows/2 ; 
    x_c = (int) backproj.cols/2 ; 

    //Centroid search solver until residual below certain tolerance: 
    while (res > TOL){ 

     m00 = 0.0 , m01 = 0.0 , m10 = 0.0 
     win.width = (int) 80; 
     win.height = (int) 60; 

     //First array element at position (x,y) "lower left corner" of the search window: 
     win.x = (int) (x_c - win.width/2) ; 
     win.y = (int) (y_c - win.height/2); 

     //Modulo correction since modulo of negative integer is negative in C: 
     if (win.x < 0) 
       win.x = win.x % backproj.cols + backproj.cols ; 

     if (win.y < 0) 
       win.y = win.y % backproj.rows + backproj.rows ; 

     for (int i = 0; i < win.height; i++){ 

       //Traverse along y-axis (height) i.e. rows ensuring wrap around top/bottom boundaries:     
       idx_row = (win.y + i) % (int)backproj.rows ; 

       for (int j = 0; j < win.width; j++){ 

         //Traverse along x-axis (width) i.e. cols ensuring wrap around left/right boundaries: 
         idx_col = (win.x + j) % (int)backproj.cols ;  
         //Compute Moments:        
         m00 += (double) backproj.at<uchar>(idx_row, idx_col) ; 
         m10 += (double) backproj.at<uchar>(idx_row, idx_col) * i ; 
         m01 += (double) backproj.at<uchar>(idx_row, idx_col) * j ; 
       } 
     } 

     //Compute new centroid coordinates of the search window: 
     x_c_new = (int) (m10/m00) ; 
     y_c_new = (int) (m01/m00); 

     //Compute the residual: 
     res = sqrt(pow((x_c_new - x_c), 2.0) + pow((y_c_new - y_c), 2.0)) ; 

     //Set new search window centroid coordinates: 
     x_c = x_c_new; 
     y_c = y_c_new; 
    } 
} 

回答

1

你的算法总是收敛到左上角独立的输入数据的原因是m00m10m01从不重置为零:

  • 在迭代0,对于每一个时刻变量m00,m10m01,你计算出正确的值m
  • 在迭代0和迭代1之间,矩变量不是r ESET并保持其先前的值
  • 因此,在迭代1,对每一个瞬间变m00m10m01,你竟然与旧的总结新的时刻,得到(M + M )
  • 在迭代2,你继续在以前的顶部和总结了新的时刻,得到(M + M + M )
  • 等,通过反复迭代。

至少应该在每次迭代开始时重置瞬间变量。

理想情况下,它们不应该是功能级别的变量,而应是块级别的变量,因为它们具有循环迭代之外没有使用(除了用于调试目的):

while (res > TOL){ 
    ... 
    double m00 = 0.0, m01 = 0.0, m10 = 0.0; 
    for (int i = 0; i < win.height; i++){ 
     ... 

EDIT 1

您遇到的第二个问题(ROI在所有地方跳跃)的原因是时刻的计算基于相对坐标ij。因此,你计算的是[avg(j),avg(i)],而你真正想要的是[avg(y),avg(x)]。为了解决这个问题,我提出了第一个解决方案。我“已经通过下面一个更简单的解决方案取代了它

EDIT 2 最简单的解决方法是正确的,在每次迭代的末尾添加ROI角的坐标:

x_c_new = win.x + (int) (m10/m00) ; 
    y_c_new = win.y + (int) (m01/m00); 
+0

感谢您指出另一个错误,我认为它应该在那之后工作,但是现在搜索窗口跳过边缘而不是聚焦于roi。那么该算法应该找到反投影图像内的概率分布模式并将搜索窗口置于该模式中心。 – Ragesam

+0

好吧,我来看看。作为Stack Overflow的一个很好的练习,你应该保留原始代码,因为它是w如。然后,在它下面,添加** EDIT **并追加描述和已经出现的新问题的更正代码。这样,答案仍然与问题的演变保持一致 –

+0

哎呀我的不好:P感谢丹尼尔的指导。我应该保留原样还是重新编辑它?此外,我不确定我是否可以在此发布git链接到整个项目?因为我觉得这对任何想要运行整个代码的人都会有帮助。 – Ragesam