0

I am using OpenCV(opencv_java248). I have one template image. This template image have logo some company. I want to know if this logo contain in other image. I got following code somewhere.

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

    Mat img = Highgui.imread(inFile);
    Mat templ = Highgui.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.5, 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 = 0.40;
    if (mmr.maxVal > threashhold) {
        Core.rectangle(img, matchLoc, new Point(matchLoc.x + templ.cols(),
                matchLoc.y + templ.rows()), new Scalar(0, 255, 0));
    }
    // Save the visualized detection.
    Highgui.imwrite(outFile, img);
}

It is working great when template and target image is of same scale. My question is how can I make it scale irrelevant ? My search image Target Image and logo Template

Bhushan
  • 1,489
  • 3
  • 27
  • 45

1 Answers1

5

Some images of what you want to match or some code would be really useful.

I don't know the Java API but did recently look into something similar written in C++. Converting should be fairly straightforward as the process will be same in either language.

Firstly perform template matching as normal, read in your images and create a mat to hold the result.

cv::Mat drawing = cv::imread(_drawing); //Read drawing
cv::Mat tmp = cv::imread(_tmp);  //Read template
cv::Mat res(drawing.rows - tmp.rows + 1, drawing.cols - tmp.cols + 1, CV_32FC1); //Create result matrix

//Perform template matching, normalise results 0 -> 1
cv::matchTemplate(tmp, drawing, res, CV_TM_CCOEFF_NORMED);
cv::threshold(res, res, 0.8, 1.0, CV_THRESH_TOZERO); //Can thresh to filter results if needed

Now that the result is populated, create variables for holding the min/max scores and their locations within the result matrix.

A tolerance value is used to filter acceptable results, where 1.0 can be seen as a 100% match and 0.25 as 25%.

//min/max values and acceptable tolerance
double min, max, tolerance = 0.90;
cv::Point minloc, maxloc; //min/max value locations

Now extract values from the result and check your max value against your tolerance, if it's within the tolerance its a match.

You can also loop this process and check through all the results to see if your image contains multiple occurences of the template.

//Loop through all results
while (true){

    //Pull out min/max values from results matrix
    cv::minMaxLoc(res, &min, &max, &minloc, &maxloc);

    //Is max within tolerance
    if (max >= tolerance){

        //Yes - Match found, do stuff //

        //Blank out that result in matrix so next highest can be extracted
        cv::floodFill(res, maxloc, cv::Scalar(0), 0, cv::Scalar(0.1), cv::Scalar(1.0));

    }
    else
        break; //No more results within tolerance, break search
}

You'll likely need to experiment with tolerances / image quality and what counts as a pass. But for simple matching this works fairly well.

Edit - Template Matching & Scale

Standard template matching performs very poorly with scaling simply because of how it works - the search window can only be as small as the provided template, so finding anything smaller (or larger) is going to be difficult.

Refining template matching for scale invariance isn't the easiest thing to do, a simple method you could try is creating scaled variations of the template (have a look at OpenCVs Image Pyramids).

There are also plenty of papers out there covering more advanced variations of template matching if interested (a Google search will bring most up).

You might want to look into feature detection which is invariant to scale and rotation.

Again, if you could post a picture of your logo and search image that would help, there might be a simple alternative.

user3510227
  • 576
  • 2
  • 6
  • 1
    I've added a little extra to my answer about scale invariance – user3510227 Aug 12 '15 at 07:20
  • That is really helpful. I have added search image and logo in edited question. You are suggesting feature detection but can you specify specific algo. which I should use coz as far as know there are number of algo. out there and some of them are patented. My very basic requirement is that they should be free and they should return some kind of confidence level of matching (ie in template matching, i get MinMaxLocResult.maxval). – Bhushan Aug 12 '15 at 07:59
  • Within OpenCV SIFT/SURF are the two patented techniques, the rest (as far as I know) are free to use, there are lots to try [see here](http://docs.opencv.org/modules/features2d/doc/feature_detection_and_description.html), FAST might be a good starting point. But from looking at your logo there might be an easier way - the triangles are the only yellow shape on the document. You could simply search for yellow pixels and if there are enough found and they are relatively near to each other (base on image size) you have a match. – user3510227 Aug 12 '15 at 08:21