【问题标题】:Template Matching with template update模板匹配与模板更新
【发布时间】:2013-12-06 11:24:03
【问题描述】:

我正在尝试使用 OpenCV/C++ 中的模板实现实时跟踪。我在每帧更新模板时遇到问题。

以下是代码:

#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)。 minmax() 函数的 ma​​tch 值每次都返回相同的值(坐标)。测试视频可在:Megamind 请仔细研究并指导...非常感谢!

编辑:如果您运行代码(带有视频),您将看到白色边界框始终位于同一位置。这是因为 minmax() 始终返回相同的“匹配”值。这个值应该随着每次更新而改变。 尝试使用 select_flag = false; 运行代码(未提交)。边界框正在根据模板移动。但在这种情况下,不会发生模板更新。

【问题讨论】:

  • 这个 youtube 视频是您程序的输入还是输出?可以在视频中看到问题吗?看起来像输出(因为跟踪了某些东西),但我有点困惑 =)如果是输出,我在哪里可以找到输入视频,它是用 select_flag 为真还是假计算的?
  • @Micka 那是输入视频。里面没有任何追踪...
  • 红色/白色矩形看起来像是在跟踪(或试图跟踪)“眼睛”。我会试试你的程序,但我不想在这样做之前转换 youtube 视频。
  • @Micka 转换什么?那是一个下载链接,它几乎没有一分钟的视频。仅当您使用视频运行代码时,才会出现白色边界框。你必须用鼠标选择初始边界框。
  • 我在谈论您发布的 youtube 视频:youtube.com/watch?v=vpnkk7N2E0Q 我看到(标记的)眼睛周围有一个红/白框。也许你上传了错误的视频?!?

标签: c++ opencv image-processing computer-vision template-matching


【解决方案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 );
}

【讨论】:

  • 非常感谢!我知道我在代码结构上犯了一个错误!!!很好的解释......现在错误很明显......
  • 我正在尝试限制模板的搜索区域。不是搜索整个图像,而是应该搜索模板周围的某些区域。那会更好。知道怎么做吗?我试过类似的东西: Rect search_region = cv::Rect(0, 0, img.cols, (img.rows/2));垫 img2 = img(search_region);然后模板匹配完成:'matchTemplate(img2, mytemplate, result, CV_TM_SQDIFF_NORMED);' 'normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat()' 但是,我无法弄清楚它将如何影响“结果”?如何进行?
  • 我建议您创建另一个问题来描述您的问题,而不是对此发表评论。
猜你喜欢
  • 2018-07-15
  • 1970-01-01
  • 2015-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多