C++ 如何在从原始图像中提取的子图像中执行模板匹配过程,并在原始图像中显示结果

C++ 如何在从原始图像中提取的子图像中执行模板匹配过程,并在原始图像中显示结果,c++,c,opencv,image-processing,template-matching,C++,C,Opencv,Image Processing,Template Matching,一整天我都在尝试使用matchtemplate函数在子图像中获取所有相关匹配,这是我已经使用mousecallback函数从原始图像中提取的ROI。下面是匹配函数的代码 ////Matching Function void CTemplate_MatchDlg::OnBnTemplatematch() { namedWindow("reference",CV_WINDOW_AUTOSIZE); while(true) { Mat ref = imread("i

一整天我都在尝试使用matchtemplate函数在子图像中获取所有相关匹配,这是我已经使用mousecallback函数从原始图像中提取的ROI。下面是匹配函数的代码

 ////Matching Function
void CTemplate_MatchDlg::OnBnTemplatematch()
 {

  namedWindow("reference",CV_WINDOW_AUTOSIZE);    
   while(true)
   { 

 Mat ref = imread("img.jpg");                    //  Original Image   
 mod_ref = cvCreateMat(ref.rows,ref.cols,CV_32F);// resizing the image to fit in picture box
 resize(ref,mod_ref,Size(),0.5,0.5,CV_INTER_AREA);

   Mat tpl =imread("Template.jpg"); // TEMPLATE IMAGE  

  cvSetMouseCallback("reference",find_mouseHandler,0);

  Mat aim=roiImg1.clone(); // SUB_IMAGE FROM ORIGINALIMAGE                   
                               // aim variable contains the ROI matrix
                               // next, want to perform template matching in that ROI                                                //                                     and display results on original image 


     if(select_flag1 == 1)
    {

        // imshow("ref",aim);

        Mat res(aim.rows-tpl.rows+1, aim.cols-tpl.cols+1,CV_32FC1);
                    matchTemplate(aim, tpl, res, CV_TM_CCOEFF_NORMED);
        threshold(res, res, 0.8, 1., CV_THRESH_TOZERO);

     while (1) 
   {
    double minval, maxval, threshold = 0.8;
    Point minloc, maxloc;
    minMaxLoc(res, &minval, &maxval, &minloc, &maxloc);

   //// Draw Bound boxes for detected templates in sub matrix

    if (maxval >= threshold)
     {
        rectangle(
            aim, 
            maxloc, 
            Point(maxloc.x + tpl.cols, maxloc.y + tpl.rows), 
            CV_RGB(0,255,0), 1,8,0
        );
        floodFill(res, maxloc, cv::Scalar(0), 0, cv::Scalar(.1), cv::Scalar(1.));
          }else
        break;
        }
     }
            ////Bounding box for ROI  selection with mouse

      rectangle(mod_ref, rect2, CV_RGB(255, 0, 0), 1, 8, 0);  // rect2 is ROI 
                       // my idea is to get all the matches in ROI with bounding boxes
                       // no need to mark any matches outside the ROI  
                       //Clearly i want to process only ROI  

    imshow("reference", mod_ref); // show the image with the results 
    waitKey(10);
    }
 //cvReleaseMat(&mod_ref);
 destroyWindow("reference");


}

/// ImplementMouse Call Back

void find_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 img3 = mod_ref.clone();
    point2 = Point(x, y);
    rectangle(img3, point1, point2, CV_RGB(255, 0, 0), 1, 8, 0);
    imshow("reference", img3);

    //  
}

if (event == CV_EVENT_LBUTTONUP && drag)
{

    Mat img4=mod_ref.clone();
            point2 = Point(x, y);
    rect1 = Rect(point1.x,point1.y,x-point1.x,y-point1.y);
            drag = 0;
    roiImg1 = mod_ref(rect1);  //SUB_IMAGE MATRIX
        imshow("reference", img4);
}

if (event == CV_EVENT_LBUTTONUP)
{
   /* ROI selected */
    select_flag1 = 1;
    drag = 0;
}
}
构建和调试过程已成功完成。但是,当我单击对话框中的匹配按钮时,我得到了错误:

Unhandled exception at 0x74bf812f in Match.exe: Microsoft C++ exception: cv::Exception at memory location 0x001ae150.. 
因此,我的想法是在与模板图像进行比较时获得子图像中的所有匹配,并在原始图像本身中显示与边界框匹配的最终结果

在这方面有人帮我吗!!非常感谢您的帮助

我下面的代码是对OpenCV提供的代码的修改

它从命令行加载一个图像并显示在屏幕上,这样用户就可以在某处绘制一个矩形来选择子图像作为模板。完成该操作后,子图像将位于绿色矩形内:

按任意键让程序执行模板匹配。将出现一个名为Template Match:的新窗口,其中显示原始图像和一个蓝色矩形,该矩形显示匹配区域:

#include <cv.h>
#include <highgui.h>
#include <iostream>


const char* ref_window = "Draw rectangle to select template";
std::vector<cv::Point> rect_points;


void mouse_callback(int event, int x, int y, int flags, void* param)
{
    if (!param)
        return;

    cv::Mat* ref_img = (cv::Mat*) param;

    // Upon LMB click, store the X,Y coordinates to define a rectangle.
    // Later this info is used to set a ROI in the reference image.
    switch (event)
    {
        case CV_EVENT_LBUTTONDOWN:
        {
            if (rect_points.size() == 0)
                rect_points.push_back(cv::Point(x, y));
        }
        break;

        case CV_EVENT_LBUTTONUP:
        {
            if (rect_points.size() == 1)
                rect_points.push_back(cv::Point(x, y));
        }
        break;

        default:
        break;
    }

    if (rect_points.size() == 2)
    {
        cv::rectangle(*ref_img, 
                      rect_points[0], 
                      rect_points[1], 
                      cv::Scalar(0, 255, 0),
                      2);

        cv::imshow(ref_window, *ref_img);
    }
}

int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        std::cout << "Usage: " << argv[0] << " <image>" << std::endl;
        return -1;
    }

    cv::Mat source = cv::imread(argv[1]);   // original image
    if (source.empty())
    {
        std::cout << "!!! Failed to load source image." << std::endl;
        return -1;
    }

    // For testing purposes, our template image will be a copy of the original.
    // Later we will present it in a window to the user, and he will select a region 
    // as a template, and then we'll try to match that to the original image.

    cv::Mat reference = source.clone(); 

    cv::namedWindow(ref_window, CV_WINDOW_AUTOSIZE);
    cv::setMouseCallback(ref_window, mouse_callback, (void*)&reference);

    cv::imshow(ref_window, reference);
    cv::waitKey(0);

    if (rect_points.size() != 2)
    {
        std::cout << "!!! Oops! You forgot to draw a rectangle." << std::endl;
        return -1;
    }

    // Create a cv::Rect with the dimensions of the selected area in the image
    cv::Rect template_roi = cv::boundingRect(rect_points);

    // Create THE TEMPLATE image using the ROI from the rectangle
    cv::Mat template_img = cv::Mat(source, template_roi);

    // Create the result matrix
    int result_cols =  source.cols - template_img.cols + 1;
    int result_rows = source.rows - template_img.rows + 1;
    cv::Mat result;

    // Do the matching and normalize
    cv::matchTemplate(source, template_img, result, CV_TM_CCORR_NORMED);
    cv::normalize(result, result, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());

    /// Localizing the best match with minMaxLoc
    double min_val = 0, max_val = 0; 
    cv::Point min_loc, max_loc, match_loc;
    int match_method = CV_TM_CCORR_NORMED;
    cv::minMaxLoc(result, &min_val, &max_val, &min_loc, &max_loc, cv::Mat());

    // When using CV_TM_CCORR_NORMED, max_loc holds the point with maximum 
    // correlation.
    match_loc = max_loc; 

    // Draw a rectangle in the area that was matched
    cv:rectangle(source, 
                 match_loc, 
                 cv::Point(match_loc.x + template_img.cols , match_loc.y + template_img.rows), 
                 cv::Scalar(255, 0, 0), 2, 8, 0 );

    imshow("Template Match:", source);
    cv::waitKey(0);

    return 0;
}

谢谢,但我得到以下错误,错误C2664:“cv::boundingRect”:无法使用1>[1>\u Ty=cv::Point 1>]1>将参数1从'std::vector'转换为'const cv::Mat&'1>,原因:无法使用1>[1>\u Ty=cv::Point 1>]1>没有可以执行此转换的用户定义的转换运算符,或者无法调用该运算符。而且,很明显,我想做的是,为用户提供选项,以选择要用作已完成的模板图像的ROI。再次,用户将在另一幅图像中选择ROI,例如:源图像1有三个面,与处理一个面的源图像相同,我们需要单独处理该部分ROI以进行匹配。如果ROI只有两个面,则模板将与两个面匹配,而不是与ROI中的第三个面匹配。不关心离开ROI的区域。并将所有匹配结果显示在源图像1的ROI中。谢谢。非常感谢您的帮助!!编译我的代码时是否会发生此错误?它是使用OpenCV 2.4.3和2.4.4成功编译的,因此将您的OpenCV升级到更新的版本应该可以解决问题。关于您想做什么,我始终建议人们在尝试使用他们不太了解的技术做更复杂的事情之前先解决一个简单的问题。在本文中,我的演示展示了一个非常简单和完整的应用程序,这样每个人都可以学习它,并用它进行实验,以了解如何进行模板匹配。一旦您了解了该方法的每一步都在做什么,您将能够调整代码以解决您感兴趣的问题。对不起,我的英语很有限,我无法理解你到底想做什么。