Ask Your Question

Detecting image in another image? (Image Comparison)

asked 2014-09-09 08:18:03 -0500

Finnish gravatar image

updated 2020-11-02 17:27:44 -0500

I would like to find a small image lets say 30x30 in a big image say 300x300. This is done by template matching and Im programming with java, I found from stackoverflow a Java version of the cpp code for template matching. It works, it finds the template image and then highlights it in source image. On purpose I search template image in a source image which it doesn't exist, the program still highlights some area on the out file. I know that it is making the best match it can. But I need to know if the image is found or not, a boolean which says true or false. Thus I should set a threshold value, what is a good value? I read it should be between 0 and 1 but I made 3 tests with 3 different source images which included the template image and got results of : 4.54... , 0, -1.86... for MinVal, am I checking the correct value? I would be glad if you can enlighten me on this and Im open for other methods as well!

Also I made these tests always with square/rectangle images, they always worked but when I cropped a circle or custom shape from source img and then searched for it, then the match is always at a wrong place... When I use a gif file for the template I get the following error:

OpenCV Error: Assertion failed ((img.depth() == CV_8U || img.depth() == CV_32F) && img.type() == templ.type()) in cv::matchTemplate, file ..\..\..\..\opencv\modules\imgproc\src\templmatch.cpp, line 249
Exception in thread "main" CvException [org.opencv.core.CvException: cv::Exception: ..\..\..    \..\opencv\modules\imgproc\src\templmatch.cpp:249: error: (-215) (img.depth() == CV_8U || img.depth() == CV_32F) && img.type() == templ.type() in function cv::matchTemplate
at org.opencv.imgproc.Imgproc.matchTemplate_0(Native Method)
at org.opencv.imgproc.Imgproc.matchTemplate(
at TemplateMatching.main(

Which file types are supported which are not?

Here is the source code Im using:

import org.opencv.core.Core;
import org.opencv.core.Core.MinMaxLocResult;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

class MatchingDemo {
public void run(String inFile, String templateFile, String outFile, int match_method) {
    System.out.println("\nRunning Template Matching");

    Mat img = Highgui.imread(inFile);
    Mat templ = Highgui.imread(templateFile);

    double minlocvalue = 7;
    double maxlocvalue = 7;

    double minminvalue = 7;
    double maxmaxvalue = 7;

    // / Create the result matrix
    int result_cols = img.cols() - templ.cols() + 1;
    int result_rows = img.rows() - templ.rows() + 1;
    Mat result = new Mat(result_rows, result_cols, CvType.CV_32FC1);

    // / Do the Matching and Normalize
    Imgproc.matchTemplate(img, templ, result, match_method);
    Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());

    // / Localizing the best match with minMaxLoc
    MinMaxLocResult mmr = Core.minMaxLoc(result);

    Point matchLoc;
    if (match_method == Imgproc.TM_SQDIFF || match_method == Imgproc.TM_SQDIFF_NORMED) {
        matchLoc = mmr.minLoc;
        minminvalue = mmr.minVal; // test 
    } else ...
edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted

answered 2014-09-10 07:27:21 -0500

updated 2014-09-10 07:29:32 -0500

Hi Deniz!

You can use the MinVal, MaxVal from the template matching output to threshold the match score. Refer this example. In this example you can see the minMaxLoc().

int threshold = 0.75;
if (maxval >= threshold)
  /// Show me what you got
  rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
  rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );   

Note that based on the Template matching type you use the limit will vary.

e.g for CV_TM_SQDIFF & CV_TM_SQDIFF_NORMED take min value. since more the correlation in both image, less the match value. And for others take MaxVal. since more the correlation, match value will be more ranges from 0-1. I think you can implement the same in java too.

Also .Gif are not supported in opencv.

These are the formats supported by opencv.

    Windows bitmaps - *.bmp, *.dib (always supported)
    JPEG files - *.jpeg, *.jpg, *.jpe (see the Notes section)
    JPEG 2000 files - *.jp2 (see the Notes section)
    Portable Network Graphics - *.png (see the Notes section)
    Portable image format - *.pbm, *.pgm, *.ppm (always supported)
    Sun rasters - *.sr, *.ras (always supported)
    TIFF files - *.tiff, *.tif (see the Notes section)
edit flag offensive delete link more


Sorry for my late reply, I had to read a little bit more and understand opencv before being able to comment. As you see Im using "TM_SQDIFF" but I made 4 tests, 3 for a good real match and 1 for a bad match all the results minval was "0" . I dont understand... Also I think it isnt possible to do template matching with any other shape other than rectangle/square right?

Finnish gravatar imageFinnish ( 2014-09-17 11:54:39 -0500 )edit

i would recommend to go with CV_TM_CCOEFF_NORMED for Template matching which gives the result 1 for 100% match & 0 for 0% match. Also if you want to use irregular shape Create a mask & apply that mask to the Template image which will improve your results.

Balaji R gravatar imageBalaji R ( 2014-09-18 01:06:34 -0500 )edit

I tried "CV_TM_CCOEFF_NORMED" but the result for a good match and a bad match was 1 :( Something is wrong but I dont know what... would you please have a look at my code? What can be wrong... Also Can you please elaborate creating a mask and applying it to the template? How can I do it?

Finnish gravatar imageFinnish ( 2014-09-18 04:06:31 -0500 )edit

I think it might have something to do with Normalizing : Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());

Finnish gravatar imageFinnish ( 2014-09-18 04:25:23 -0500 )edit

After removing the Normalizing line on above comment I started to get values for "CV_TM_CCOEFF_NORMED" 0.999988345 for goot matches and 0.34534643 , 0,454645645 , 0,5131431454 for bad matches I guess this is something I can start with ... lets say under 0,75 is false and above true? Would you suggest improvements? Better ideas of detection?

Finnish gravatar imageFinnish ( 2014-09-18 05:05:39 -0500 )edit

yes that's it. Play around with it:)

Balaji R gravatar imageBalaji R ( 2014-09-18 09:15:13 -0500 )edit

Please mark this as an answer if you found what you have asked.

Balaji R gravatar imageBalaji R ( 2014-09-18 09:29:23 -0500 )edit

Question Tools


Asked: 2014-09-09 08:18:03 -0500

Seen: 8,769 times

Last updated: Sep 10 '14