Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

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)
cv2.waitKey(0)

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 aspect. Or not.