Template Matching With Multiple Objects In Opencv Python
Solution 1:
One way to find multiple matches is to write over the found matches and run the match again. Edit: A better way to find multiple matches is to write over the results. In the first example we fill the matched part of results with zeroes (use ones for SQDIFF or CCORR_NORMED) , and then look for the next match in a loop.
import cv2
import numpy as np
import time
image = cv2.imread('smiley.png', cv2.IMREAD_COLOR )
template = cv2.imread('template.png', cv2.IMREAD_COLOR)
h, w = template.shape[:2]
method = cv2.TM_CCOEFF_NORMED
threshold = 0.90
start_time = time.time()
res = cv2.matchTemplate(image, template, method)
# fake out max_val for first run through loop
max_val = 1while max_val > threshold:
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
if max_val > threshold:
res[max_loc[1]-h//2:max_loc[1]+h//2+1, max_loc[0]-w//2:max_loc[0]+w//2+1] = 0
image = cv2.rectangle(image,(max_loc[0],max_loc[1]), (max_loc[0]+w+1, max_loc[1]+h+1), (0,255,0) )
cv2.imwrite('output.png', image)
input image:
use the eyes as template images (since there is more than one eye!)
output:
And here is the original way I did it by writing over the image. This way is way is much slower because we do n+1 matchTemplate
operations for n matches. By one measurement, this technique is 1000 times slower.
import cv2
import numpy as np
image = cv2.imread('smiley.png', cv2.IMREAD_COLOR )
template = cv2.imread('template.png', cv2.IMREAD_COLOR)
h, w = template.shape[:2]
method = cv2.TM_CCOEFF_NORMED
threshold = 0.95# fake out max_val for first run through loop
max_val = 1while max_val > threshold:
res = cv2.matchTemplate(image, template, method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# using top ranked score, fill in that area with green
image[max_loc[1]:max_loc[1]+h+1:, max_loc[0]:max_loc[0]+w+1, 0] = 0# blue channel
image[max_loc[1]:max_loc[1]+h+1:, max_loc[0]:max_loc[0]+w+1, 1] = 255# green channel
image[max_loc[1]:max_loc[1]+h+1:, max_loc[0]:max_loc[0]+w+1, 2] = 0# red channel
cv2.imwrite('output.png', image)
output image:
Solution 2:
While running bfris' method for my own dataset, I noticed that the while
loop can stuck indefinitely in some special cases so here is my improved version:
import cv2
import numpy as np
import time
image = cv2.imread('smiley.png', cv2.IMREAD_COLOR )
template = cv2.imread('template.png', cv2.IMREAD_COLOR)
h, w = template.shape[:2]
method = cv2.TM_CCOEFF_NORMED
threshold = 0.90
start_time = time.time()
res = cv2.matchTemplate(image, template, method)
# fake out max_val for first run through loop
max_val = 1
prev_min_val, prev_max_val, prev_min_loc, prev_max_loc = None, None, None, Nonewhile max_val > threshold:
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# Prevent infinite loop. If those 4 values are the same as previous ones, break the loop.if prev_min_val == min_val and prev_max_val == max_val and prev_min_loc == min_loc and prev_max_loc == max_loc:
breakelse:
prev_min_val, prev_max_val, prev_min_loc, prev_max_loc = min_val, max_val, min_loc, max_loc
if max_val > threshold:
# Prevent start_row, end_row, start_col, end_col be out of range of image
start_row = max_loc[1] - h // 2if max_loc[1] - h // 2 >= 0else0
end_row = max_loc[1] + h // 2 + 1if max_loc[1] + h // 2 + 1 <= res.shape[0] else res.shape[0]
start_col = max_loc[0] - w // 2if max_loc[0] - w // 2 >= 0else0
end_col = max_loc[0] + w // 2 + 1if max_loc[0] + w // 2 + 1 <= res.shape[1] else res.shape[0]
res[start_row: end_row, start_col: end_col] = 0
image = cv2.rectangle(image,(max_loc[0],max_loc[1]), (max_loc[0]+w+1, max_loc[1]+h+1), (0,255,0) )
cv2.imwrite('output.png', image)
Post a Comment for "Template Matching With Multiple Objects In Opencv Python"