2015-10-26 22 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