我一直在尝试实现用于跟踪对象的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中的块级变量而不是函数级变量,感谢Daniel 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;
}
}
答案 0 :(得分:1)
您的算法始终收敛到左上角而与输入数据无关的原因是m00
,m10
和m01
永远不会重置为零:
m00
,m10
和m01
,您计算正确的值m 0 m00
,m10
和m01
,您实际上将新时刻与旧时刻相加并获得(m 0 < / sub> + m 1 )至少,应该在每次迭代开始时重置时刻变量。
理想情况下,它们不应该是函数级变量,而应该是块级变量,因为它们在循环迭代之外没有用处(除了调试目的):
while (res > TOL){
...
double m00 = 0.0, m01 = 0.0, m10 = 0.0;
for (int i = 0; i < win.height; i++ ){
...
编辑1
您遇到的第二个问题(ROI遍布整个地方)的原因是,时刻的计算基于相对坐标i
和j
。
因此,你计算的是[avg(j),avg(i)],你真正想要的是[avg(y),avg(x)]。为了解决这个问题,我提出了第一个解决方案。我已经用下面一个更简单的解决方案取代了它。
编辑2 最简单的解决方案是在每次迭代结束时添加ROI角的坐标:
x_c_new = win.x + (int) ( m10 / m00 ) ;
y_c_new = win.y + (int) ( m01 / m00 );