Сопоставление шаблона с обновлением шаблона

Я пытаюсь реализовать отслеживание в реальном времени с использованием шаблонов в OpenCV/С++. Я столкнулся с проблемой обновления шаблона с каждым кадром.

Ниже приведен код:

#include <iostream>
#include "opencv2/opencv.hpp"
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/objdetect/objdetect.hpp>

#include <sstream>


using namespace cv;
using namespace std;

Point point1, point2; /* vertical points of the bounding box */
int drag = 0;
Rect rect; /* bounding box */
Mat img, roiImg; /* roiImg - the part of the image in the bounding box */
int select_flag = 0;
bool go_fast = false;

Mat mytemplate;


///------- template matching -----------------------------------------------------------------------------------------------

Mat TplMatch( Mat &img, Mat &mytemplate )
{
  Mat result;

  matchTemplate( img, mytemplate, result, CV_TM_SQDIFF_NORMED );
  normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );

  return result;
}


///------- Localizing the best match with minMaxLoc ------------------------------------------------------------------------

Point minmax( Mat &result )
{
  double minVal, maxVal;
  Point  minLoc, maxLoc, matchLoc;

  minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
  matchLoc = minLoc;

  return matchLoc;
}


///------- tracking --------------------------------------------------------------------------------------------------------

void track()
{
    if (select_flag)
    {
        roiImg.copyTo(mytemplate);
//         select_flag = false;   //select_flag is kept false so that new template can
        go_fast = true;           //copied to 'mytemplate' for each iteration
    }

//     imshow( "mytemplate", mytemplate ); waitKey(0);

    Mat result  =  TplMatch( img, mytemplate );
    Point match =  minmax( result );  //PROBLEM: "match" always returning same value!!!

    rectangle( img, match, Point( match.x + mytemplate.cols , match.y + mytemplate.rows ), CV_RGB(255, 255, 255), 0.5 );

    std::cout << "match: " << match << endl;

    /// template update step
    Rect ROI = cv::Rect( match.x, match.y, mytemplate.cols, mytemplate.rows );
    roiImg = img( ROI );
    imshow( "roiImg", roiImg ); //waitKey(0);
}


///------- MouseCallback function ------------------------------------------------------------------------------------------

void mouseHandler(int event, int x, int y, int flags, void *param)
{
    if (event == CV_EVENT_LBUTTONDOWN && !drag)
    {
        /// left button clicked. ROI selection begins
        point1 = Point(x, y);
        drag = 1;
    }

    if (event == CV_EVENT_MOUSEMOVE && drag)
    {
        /// mouse dragged. ROI being selected
        Mat img1 = img.clone();
        point2 = Point(x, y);
        rectangle(img1, point1, point2, CV_RGB(255, 0, 0), 3, 8, 0);
        imshow("image", img1);
    }

    if (event == CV_EVENT_LBUTTONUP && drag)
    {
        point2 = Point(x, y);
        rect = Rect(point1.x, point1.y, x - point1.x, y - point1.y);
        drag = 0;
        roiImg = img(rect);
    }

    if (event == CV_EVENT_LBUTTONUP)
    {
        /// ROI selected
        select_flag = 1;
        drag = 0;
    }

}



///------- Main() ----------------------------------------------------------------------------------------------------------

int main()
{
    int k;

    ///open video file
    VideoCapture cap;
    cap.open( "Megamind.avi" );
    if ( !cap.isOpened() )
    {   cout << "Unable to open video file" << endl;    return -1;    }

    cap >> img;
    GaussianBlur( img, img, Size(7,7), 3.0 );
    imshow( "image", img );

    while (1)
    {
        cap >> img;
        if ( img.empty() )
            break;

        // Flip the frame horizontally and add blur
        cv::flip( img, img, 1 );
        GaussianBlur( img, img, Size(7,7), 3.0 );

        if ( rect.width == 0 && rect.height == 0 )
            cvSetMouseCallback( "image", mouseHandler, NULL );
        else
            track();

        imshow("image", img);
        k = waitKey(go_fast ? 30 : 10000);
        if (k == 27)
            break;
    }

    return 0;
}

Обновленный шаблон не отслеживается. Я не могу понять, почему это происходит, так как я обновляю свой шаблон (roiImg) с каждой итерацией. Значение match из функции minmax() каждый раз возвращает одно и то же значение (координаты). Тестовое видео доступно по адресу: Megamind Пожалуйста, изучите его и направьте вперед... большое спасибо!

EDIT: если вы запустите код (с видео), вы увидите, что белая ограничивающая рамка всегда находится в одном и том же месте. Это связано с тем, что minmax() все время возвращает одно и то же значение «совпадения». Это значение должно меняться при каждом обновлении. Попробуйте запустить код с параметром select_flag = false; (не зафиксировано). Ограничивающая рамка движется в соответствии с шаблоном. Но в этом случае обновление шаблона не происходит.


person learner    schedule 06.12.2013    source источник
comment
это видео на YouTube вход или выход вашей программы? Можно ли увидеть проблему на видео? Похоже на вывод (поскольку что-то отслеживается), но я немного запутался =) Если это вывод, то где я могу найти входное видео и было ли оно вычислено с select_flag, равным true или false ?   -  person Micka    schedule 06.12.2013
comment
@Micka это входное видео. В нем ничего не отслеживается...   -  person learner    schedule 06.12.2013
comment
Красно-белый прямоугольник выглядит как отслеживание (или попытка отслеживания) глаза. Я бы попробовал вашу программу, но я не хочу конвертировать видео на YouTube перед этим.   -  person Micka    schedule 06.12.2013
comment
@Micka преобразовать что? это ссылка для скачивания, это едва ли минутное видео. белая ограничивающая рамка появляется, только если вы запускаете код с видео. вы должны выбрать начальную ограничительную рамку с помощью мыши.   -  person learner    schedule 06.12.2013
comment
Я говорю о размещенном вами видео на YouTube: youtube.com/watch?v=vpnkk7N2E0Q Я вижу красно-белую рамку вокруг (отмеченного) глаза. Может быть вы загрузили не то видео?!?   -  person Micka    schedule 06.12.2013
comment
@Мика ааа ок! извините за дт! пожалуйста, найдите видео по адресу: code.ros.org/trac/opencv/export/7237/trunk/opencv/samples/cpp/   -  person learner    schedule 06.12.2013
comment
Уже нашел видео, не знал, что там была ваша оригинальная публикация (ссылка в видео на YouTube). stackoverflow.com/questions/20180073/ Но сегодня у меня не осталось времени... надеюсь, в понедельник я найду время, чтобы протестировать ваш код!   -  person Micka    schedule 06.12.2013
comment
@ Мика, да ... там не было особого ответа. Я уверен, что это незначительная проблема дизайна, которую я не могу понять! Шаблон обновляется каждый раз (последние 3 строки функции track()), но minmax() почему-то не обновляется... надеюсь, вы что-нибудь найдете!   -  person learner    schedule 06.12.2013


Ответы (1)


Проблема именно в этом разделе:

if (select_flag)
{
    roiImg.copyTo(mytemplate);
    // select_flag = false;   //select_flag is kept false so that new template can
    // ^^^^^^^^^^^ WRONG
    go_fast = true;           //copied to 'mytemplate' for each iteration
}

На самом деле вам нужно установить select_flag равным false на первой итерации. В противном случае вы просто копируете то, что находится на текущем изображении в этом кадре, в свой шаблон, и, конечно же, вы найдете это точно в том же месте!

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

void track()
{
  std::cout << select_flag << std::endl;

    if (select_flag)
    {
        roiImg.copyTo(mytemplate);
        select_flag = false;   //select_flag is kept false so that new template can
        go_fast = true;           //copied to 'mytemplate' for each iteration

    }

//     imshow( "mytemplate", mytemplate ); waitKey(0);

    Mat result  =  TplMatch( img, mytemplate );

    imshow("match", result);

    Point match =  minmax( result );  //PROBLEM: "match" always returning same value!!!

    std::cout << "match: " << match << endl;

    /// template update step
    Rect ROI = cv::Rect( match.x, match.y, mytemplate.cols, mytemplate.rows );

    std::cout << ROI << std::endl;

    roiImg = img( ROI );
    imshow( "roiImg", roiImg ); //waitKey(0);

    // Update the template AFTER tracking has occurred to carry it over to the next frame
    roiImg.copyTo(mytemplate);
    imshow("mytemplate", mytemplate);

    // Draw onto the image AFTER all accesses are performed
    rectangle( img, match, Point( match.x + mytemplate.cols , match.y + mytemplate.rows ), CV_RGB(255, 255, 255), 0.5 );
}
person aardvarkk    schedule 06.12.2013
comment
большое спасибо! я знал, что делаю ошибку в структуре кода!!! хорошее объяснение, а также... теперь ошибка ясна... - person learner; 06.12.2013
comment
я пытаюсь ограничить область поиска для шаблона. Вместо поиска по всему изображению может потребоваться поиск в некоторой области вокруг шаблона. Это было бы лучше. Любая идея, как это сделать? Я пробовал что-то вроде: Rect search_region = cv::Rect(0, 0, img.cols, (img.rows/2)); Мат img2 = img (регион_поиска); а затем сопоставление шаблона выполняется с помощью: 'matchTemplate (img2, mytemplate, result, CV_TM_SQDIFF_NORMED);' 'normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat()' Но я не могу понять, как это повлияет на результат? Что делать дальше? - person learner; 19.12.2013
comment
Я бы рекомендовал вам создать еще один вопрос, описывающий вашу проблему, вместо того, чтобы комментировать этот. - person aardvarkk; 20.12.2013