Ask Your Question

Template matching-multiple objects

asked 2017-07-12 17:24:31 -0600

ssamko gravatar image

updated 2018-12-27 20:40:16 -0600

Helo guys I am new here and need Help with getting all locations from MatchTemplate. I use Emgu wrapper but I appreciate also c++ code samples. I use OpenCV 3.2

So my problem is that with MinMax I get only 1 location of template searched on source image(but on this image is about 10 objects same like template) so I want to get locations of all. I saw many examples of FloodFill with which it should be possible(in older OpenCV versions) but I am not able to edit it to my needs.

How do MinMax function access to result of MatchTemplate ? Can I get those locations manually from result without any function ?

My source codepreview from stack owerflow:

PS: I do this for about 3 days without success, so I would be very thankful for help.


edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted

answered 2017-07-13 04:39:33 -0600

alkasm gravatar image

minMaxLoc() simply gives you the absolute minimum and maximum values, so you cannot grab multiple values with this function. You can do a couple different tricks to grab multiple values. The best idea is not to grab simply the 10 lowest (or highest, depending on method) pixels locations if you have 10 objects, because wherever the minimum and maximum exist, the pixel neighbors of that will probably have similar high/low values too. Instead, the typical method is to define a threshold, where all the values below (or above, depending on method) the threshold count as a "detection". Of course, this threshold will depend on the image, and template, and method---so it's not immediately obvious how to define the right number. However, you have some help---namely, you know the value of the min/max from minMaxLoc(), so you can let this define your threshold. For example, if you were trying to find the minimum of the following array:

[5, 8, 3, 9, 1, 4, 7, 1.1]

You would get 1 as the minimum and 4 as the index of the minimum from minMaxLoc(). Well, if you wanted to get numbers close to that minimum, you could grab the minimum, maybe multiply it to give a little more leeway, and find all values less than that. For this example, maybe you'd multiply your minimum by 1.5, and then find all the values and indices of the array under 1.5.

So specifically, find minMaxLoc() multiply your minimum by some number over 1 (or your maximum by some number under 1) to give a little bit of leeway, and find all elements (by searching or any other method you have available) less than/greater than that multiplied min/max.

Here's a short python program which accomplishes what you're after. Sorry for not being in the language you want, but it should be fairly easy to translate:

import cv2
import numpy as np

# read image
img = cv2.imread('01.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
template = cv2.imread('block.png',0)

# run template matching, get minimum val
res = cv2.matchTemplate(gray, template, cv2.TM_SQDIFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

# create threshold from min val, find where sqdiff is less than thresh
min_thresh = (min_val + 1e-6) * 1.5
match_locations = np.where(res<=min_thresh)

# draw template match boxes
w, h = template.shape[::-1]
for (x, y) in zip(match_locations[1], match_locations[0]):
    cv2.rectangle(img, (x, y), (x+w, y+h), [0,255,255], 2)

# display result
cv2.imshow('', img)

Yielding the following image:

Multiple template matches

Notice that in my program I added a small number (1e-6 or 0.000001) to the number before multiplying in case the minimum was 0 (which it was in my case, since the match is exact---the template was taken directly from the image). If you're working with real images where template isn't a strictly exact copy of a part of the image, then you can probably neglect that ... (more)

edit flag offensive delete link more


Thank you, now I understand whole concept and also your python code but I really dont know how to rewrite this line: "match_locations = np.where(res<=min_thresh)" to working C# code. Other things are clear to me now. I will sit by the PC until I figure it out.

ssamko gravatar imagessamko ( 2017-07-13 06:50:52 -0600 )edit

Yeah that's a pretty numpy-python specific operation. It returns the pixel locations where the result is less than idea what a C# implementation would look like for that line.

alkasm gravatar imagealkasm ( 2017-07-13 07:14:51 -0600 )edit

Question Tools

1 follower


Asked: 2017-07-12 17:24:31 -0600

Seen: 15,556 times

Last updated: Jul 13 '17