Template matching false positive

962 views Asked by At

I am using template matching on openCV java to identify if a subimage exist in larger image. I want to get coordinates of match only if exact subimage is available in larger image. I am using this code but getting a lot of false positive. Attached is the subimage and larger image. Subimage is not present in larger image but i am getting match at (873,715) larger image subimage

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

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

    // / 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());
    Imgproc.threshold(result, result, 0.1, 1.0, Imgproc.THRESH_TOZERO);
    // / 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;
    } else {
        matchLoc = mmr.maxLoc;
    }
    double threashhold = 1.0;
    if (mmr.maxVal > threashhold) {
        System.out.println(matchLoc.x+" "+matchLoc.y);  
       Imgproc.rectangle(img, matchLoc, new Point(matchLoc.x + templ.cols(),
                matchLoc.y + templ.rows()), new Scalar(0, 255, 0));
    }
    // Save the visualized detection.
    Imgcodecs.imwrite(outFile, img);
}
2

There are 2 answers

0
Hardtack On

I am not familiar with OpenCV in Java but OpenCV C++.

I don't think following code is necessary.

Imgproc.threshold(result, result, 0.1, 1.0, Imgproc.THRESH_TOZERO);

The min/max values of 'Mat result' will be between -1 and 1 if you uses normalized option. Therefore, your following code will not work because your threshold is 1.0 if you use normalized option.

if (mmr.maxVal > threshold) 

Also, if you use CV_TM_SQDIFF, above code should be

if (mmr.minVal < threshold)

with proper threshold.

How about drawing minMaxLoc before comparing minVal/maxVal with threshold? to see it gives correct result? because match at (873,715) is ridiculous.

1
brad On

Here is an answer of the same question: Determine if an image exists within a larger image, and if so, find it, using Python

You will have to convert the python code to Java