Алгоритм среднего сдвига для отслеживания объектов выдает вычисление центроида обновления окна поиска

Я пытался реализовать алгоритм среднего смещения для отслеживания объектов и рассмотрел связанные с ним концепции.

На данный момент мне удалось успешно сгенерировать обратно проецируемый поток с моей камеры с одноканальной гистограммой hue roi и одноканальным видеопотоком hue, который выглядит нормально, я знаю, что в библиотеке opencv есть функция среднего смещения, но я пытаюсь реализовать один сам, используя структуры данных, предоставленные в opencv, вычисляя моменты и вычисляя средний центр тяжести окна поиска.

Но по какой-то причине я не могу найти проблему в своем коде, поскольку он продолжает сходиться к верхнему левому углу моего видеопотока для отслеживания любой области ввода (интересующей области). Ниже приведен фрагмент кода функции для вычисления центроида окна поиска, где я чувствую проблему, но не уверен, в чем она заключается, я был бы очень признателен, если бы кто-нибудь мог указать мне правильное направление:

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 за указание на это, но проблема все еще остается. Теперь окно поиска перемещается по границам кадра, а не фокусируется на области интереса.

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

person Ragesam    schedule 26.10.2015    source источник


Ответы (1)


Причина, по которой ваши алгоритмы всегда сходятся к верхнему левому углу независимо от входных данных, заключается в том, что m00, m10 и m01 никогда не обнуляются:

  • На итерации 0 для каждой переменной момента m00, m10 и m01 вы вычисляете правильное значение m0
  • Между итерацией 0 и итерацией 1 переменные моментов не сбрасываются и сохраняют свое предыдущее значение.
  • Таким образом, на итерации 1 для каждой переменной момента m00, m10 и m01 вы фактически суммируете новый момент со старым и получаете ( m0 + m1 )
  • На итерации 2 вы продолжаете суммировать новые моменты поверх предыдущих и получаете ( m0 + m1 + m2 )
  • И так далее, итерация за итерацией.

По крайней мере, переменные момента должны сбрасываться в начале каждой итерации.

В идеале они не должны быть переменными уровня функции, а должны быть переменными уровня блока, поскольку они не используются вне итераций цикла (кроме целей отладки):

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 Самое простое решение — добавить координаты угла области интереса прямо в конце каждой итерации:

    x_c_new = win.x + (int) ( m10 / m00 ) ;
    y_c_new = win.y + (int) ( m01 / m00 );
person Daniel Strul    schedule 26.10.2015
comment
Спасибо, что указали на другую ошибку. Я думал, что после этого она должна работать, но теперь окно поиска прыгает по краям, а не фокусируется на области интереса. Предполагается, что алгоритм находит режимы распределения вероятностей в обратно проецированном изображении и центрирует окно поиска на этом режиме. - person Ragesam; 27.10.2015
comment
Хорошо, я посмотрю. В качестве хорошей практики в Stack Overflow лучше оставить исходный код как есть. Затем под ним вы добавляете EDIT и добавляете описание и исправленный код новой возникшей проблемы. Таким образом, ответы остаются в соответствии с эволюцией вопроса - person Daniel Strul; 27.10.2015
comment
К сожалению, мой плохой: P спасибо за руководство Даниэль. Оставить как есть или отредактировать? Более того, я не уверен, могу ли я опубликовать здесь ссылку git на весь проект? так как я чувствую, что это будет полезно для всех, кто хочет запустить весь код. - person Ragesam; 27.10.2015
comment
@Ragesam Будет лучше, если ты отредактируешь заново. На данный момент я не проверял новую проблему, просто уточнил свой предыдущий ответ. Что касается правил размещения ссылок на github, я действительно не знаю правил. На самом деле мне нужна дополнительная информация, чтобы продолжить, но не весь проект: - какова структура Mat и Rect? Можно ли показать небольшую выборку данных backproj (примерно 10 баллов) и значения win? Спасибо - person Daniel Strul; 27.10.2015
comment
Я надеюсь, что теперь это выглядит намного лучше :), Mat (тип данных opencv) представляет собой одноканальный массив оттенков со значениями обратного прогнозирования распределения вероятностей между 0,255, т.е. значениями, близкими к 255 в областях видеопотока, где гистограмма оттенка roi соответствует оттенку видеопотока. в противном случае он имеет значение 0. Rect (также тип данных opencv) определяет прямоугольную область, в моем случае она представлена ​​​​переменной «win», где (win.x, win.y) = (0,0) координаты прямоугольник больше похож на двумерный массив, а win.width x win.height — это размер массива. Я надеюсь, что это поможет, я довольно плохо объясняю - person Ragesam; 27.10.2015
comment
@Ragesam Да, спасибо! Я обновил свой ответ, чтобы объяснить ваше поведение, прыгающее через окно, простое исправление должно исправить это. - person Daniel Strul; 27.10.2015
comment
в последнем комментарии есть поправка (win.x, win.y) не равно (0,0), а представляет собой глобальные координаты нижнего левого угла окон поиска в пределах изображения обратной проекции. - person Ragesam; 27.10.2015
comment
@Ragesam Да, я так и предполагал. вот почему вам нужно интегрировать [win.x, win.y] в какой-то момент ваших вычислений. Прямо сейчас вы не вычисляете [среднее (x), среднее (y)), вы вычисляете [среднее (i) , среднее(j) ]. Таким образом компенсируются ошибкой [deltax, deltay] = [среднее(x), среднее(y)] - [среднее(i), среднее(j)] = [-win.x, -win.y] - person Daniel Strul; 27.10.2015
comment
Готово, я переписал ответ, чтобы предоставить вам лучшее решение (более простое, но также более эффективное и точное) - person Daniel Strul; 27.10.2015
comment
Большое спасибо, я не могу представить, что упустил из виду работу с глобальными координатами изображения. В любом случае, вы помогли мне найти не одну ошибку, а целых 3 :) и теперь она работает нормально. - person Ragesam; 27.10.2015