I am trying to do some dynamic template matching with cv2.matchTemplate
. The template is:
and the image I am matching it to is:
I am adjusting the size and angle of the template and then grabbing maxVal
and maxLoc
from cv2.matchTemplate
and storing them in a dict
with maxVal
as the keys. I'm then grabbing max(data.keys())
as the "best" match from result = cv2.matchTemplate(image, resized_template, cv2.TM_CCORR_NORMED)
. When I loop through all of the keys and plot them on the image, there are some that find the mickey head much better than max(data.keys())
.
This is the region for "best" match:
#Find best match from scores
best_match = max(scores.keys())
#Output image
image_copy = color_image.copy()
#Create rectangle around best match
cv2.rectangle(image_copy, (data[best_match][1][0], data[best_match][1][1]), (data[best_match][1][0] + data[best_match][0][0], data[best_match][1][1] + data[best_match][0][1]), (255, 255, 255), 2)
plt.imshow(image_copy)
But this region appears to locate it much more accurately:
image_copy = color_image.copy()
for n in list(data.keys())[69:70:1]:
#Create rectangle around best match
cv2.rectangle(image_copy, (data[n][1][0], data[n][1][1]), (data[n][1][0] + data[n][0][0], data[n][1][1] + data[n][0][1]), (255, 255, 255), 2)
cv2.imwrite('output_1.jpg', image_copy)
plt.imshow(image_copy)
Am I miss interpreting what the maxVal
from cv2.matchTemplate
actually represents? If so, how can I select the actual "best" region based on some value or criteria? Here's the full code:
#Import packages
import numpy as np
import matplotlib.pyplot as plt
import cv2
import imutils
import os
#Import template
template = cv2.imread(templates_dir + '\\' + os.listdir(templates_dir)[3])
gray_template = cv2.cvtColor(template, cv2.COLOR_RGB2GRAY)
#Import image
image = cv2.imread(images_dir + '\\' + os.listdir(images_dir)[5])
color_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
#Image dims
image_h = image.shape[1]
image_w = image.shape[0]
#Processing loop scaling the template
#Scores dict
scores = {}
#Data dict of structure (maxVal: (template dims, locs, angle))
data = {}
#Edge images
template = cv2.Canny(gray_template, 80, 200)
image = cv2.Canny(gray_image, 80, 200)
#Loop through different template scales
for scale in np.linspace(0.2, 1.5, 15):
#Loop through different template rotations
for angle in np.linspace(0, 360, 25)[:-1]:
#Rotate template
template_rotated = imutils.rotate(template, angle)
#Resize template
resized_template = imutils.resize(template_rotated, width = int(template_rotated.shape[0] * scale))
#Dims of resized template
template_h = resized_template.shape[1]
template_w = resized_template.shape[0]
#Break from loop if the template becomes bigger than the image
if template_h > image_h or template_w > image_w:
break
#Run template through image
result = cv2.matchTemplate(image, resized_template, cv2.TM_CCORR_NORMED)
#Get matching score and location
(_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)
#Add correlation value and result to scores
scores[str(maxVal)] = result
#Add info to data
data[str(maxVal)] = ((template_h, template_w), (maxLoc[0], maxLoc[1]), angle)
#Find best match from scores
best_match = max(scores.keys())
#Output image
image_copy = color_image.copy()
#Create rectangle around best match
cv2.rectangle(image_copy, (data[best_match][1][0], data[best_match][1][1]), (data[best_match][1][0] + data[best_match][0][0], data[best_match][1][1] + data[best_match][0][1]), (0, 0, 255), 2)
plt.imshow(image_copy)