Opencv matchTemplate not matching

Miguel Cantó Bataller picture Miguel Cantó Bataller · Oct 29, 2014 · Viewed 9.3k times · Source

I'm using OpenCV 3.0.0 to locate an image into another image. A priori the function matchTemplate is what i need to use, but seeing the results i am not sure anymore.

The problem is that depending on the input images, the result is perfectly accurate or completely inaccurate.

Example 1:

Main image

Simple

Template

Simple

Result

Simple

No complaints here. The matching is perfect in this case. But now i replace the images for the ones i want to use and...

Main image

Complex

Template

Complex

Result

enter image description here

So, not working at all (result rectangle on top right of the image). Any of the methods (in this example CORR NORMED) prints the rectangle where the template is located. All the results are far away from being accurate.

So, my question is, does the result of matchTemplate depend on how many different colors/shapes the main image has? Would SURF or SIFT help me here? Do you guys now any function that would help me locate a template into another image?

Thank you in advance!

PS: I didn't add any code because i guess is not that kind of problem, since the first example works well.

Answer

Micka picture Micka · Oct 29, 2014

Your problem might be, that template matching isnt scale invariant, your template size doestn fit the objects size.

Using this input, and code I get that output:

input image:

enter image description here

input template:

enter image description here

code: taken basically from opencv tutorial: http://docs.opencv.org/doc/tutorials/imgproc/histograms/template_matching/template_matching.html

int main()
{
    cv::Mat input = cv::imread("../inputData/TemplateMatch.jpg");

    cv::Mat gray;
    cv::cvtColor(input,gray,CV_BGR2GRAY);

    cv::Mat templ = cv::imread("../inputData/Template2.jpg");

    cv::Mat img = input;
    cv::Mat result;
    /// Create the result matrix
    int result_cols =  img.cols - templ.cols + 1;
    int result_rows = img.rows - templ.rows + 1;

    result.create( result_cols, result_rows, CV_32FC1 );

    int match_method = CV_TM_SQDIFF;

    /// Do the Matching and Normalize
    matchTemplate( img, templ, result, match_method  );
    normalize( result, result, 0, 1, cv::NORM_MINMAX, -1, cv::Mat() );

    /// Localizing the best match with minMaxLoc
    double minVal; double maxVal; cv::Point minLoc; cv::Point maxLoc;
    cv::Point matchLoc;

    minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat() );

    /// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better
    if( match_method  == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
    { matchLoc = minLoc; }
    else
    { matchLoc = maxLoc; }

    /// Show me what you got
    cv::rectangle( input, matchLoc, cv::Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), cv::Scalar::all(0), 2, 8, 0 );
    cv::rectangle( result, matchLoc, cv::Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), cv::Scalar::all(0), 2, 8, 0 );


    cv::imshow("input", input);
    cv::imshow("template", templ);

    cv::imwrite("../outputData/TemplateMatch.jpg", input);
    cv::waitKey(0);
    return 0;
}

output:

enter image description here