模板匹配是一种常用的图像处理技术,它用于在一幅图像中寻找与给定模板最匹配的区域(在一副大图中搜寻查找模版图像位置的方法)。模板匹配的基本思想是将模板图像在目标图像上滑动,并计算它们的相似度,找到相似度最高的位置即为匹配位置。
cv2.matchTemplate()
函数是OpenCV中用于模板匹配的函数。它的语法如下:
cv2.matchTemplate(image, template, method, result=None, mask=None)
参数说明:
image
:目标图像,即待搜索的图像。template
:模板图像,即待匹配的图像。method
:匹配方法,可以是以下几种方法之一:
cv2.TM_SQDIFF
:平方差匹配法。cv2.TM_SQDIFF_NORMED
:归一化平方差匹配法。cv2.TM_CCORR
:相关匹配法。cv2.TM_CCORR_NORMED
:归一化相关匹配法。cv2.TM_CCOEFF
:相关系数匹配法。cv2.TM_CCOEFF_NORMED
:归一化相关系数匹配法。result
:可选参数,用于存储匹配结果的数组。mask
:可选参数,用于指定感兴趣区域的掩码。算法步骤:
1.加载目标图像和模板图像。
2.将模板图像在目标图像上滑动,计算每个位置的相似度。
3.找到相似度最高的位置即为匹配位置。
具体实现方法如下(使用Python的OpenCV库):
import cv2
import numpy as np
# 加载目标图像和模板图像
target_img = cv2.imread('target.jpg')
template_img = cv2.imread('template.jpg')
# 获取目标图像和模板图像的宽高
target_h, target_w = target_img.shape[:2]
template_h, template_w = template_img.shape[:2]
# 使用平方差匹配算法
result = cv2.matchTemplate(target_img, template_img, cv2.TM_SQDIFF)
# 获取最匹配的位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
top_left = min_loc
bottom_right = (top_left[0] + template_w, top_left[1] + template_h)
# 在目标图像上绘制矩形框
cv2.rectangle(target_img, top_left, bottom_right, (0, 255, 0), 2)
# 显示结果图像
cv2.imshow('Result', target_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
在上述代码中,我们首先加载了目标图像和模板图像,然后使用cv2.matchTemplate()
函数进行模板匹配,得到匹配结果。最后,通过cv2.minMaxLoc()
函数找到最匹配的位置,并在目标图像上绘制矩形框来表示匹配位置。
需要注意的是,模板匹配算法的结果可能受到光照、尺度、旋转等因素的影响。因此,在实际应用中,可能需要对图像进行预处理或使用其他更复杂的匹配算法来提高匹配的准确性。
cv2.matchTemplate()
函数会在目标图像中搜索与模板图像相似的区域,并返回一个匹配结果矩阵。匹配结果矩阵的每个元素表示该位置与模板的匹配程度,值越小表示匹配程度越高。在使用
cv2.matchTemplate()
函数时,需要根据具体的需求选择合适的匹配方法。常用的是平方差匹配法和相关系数匹配法。平方差匹配法适用于目标图像与模板图像具有明显的区别,相关系数匹配法适用于目标图像与模板图像具有相似的特征。在使用匹配结果进行进一步处理时,可以通过设置匹配阈值来筛选出符合要求的匹配位置。只有匹配结果低于阈值的位置才会被认为是匹配的位置。
需要注意的是,
cv2.matchTemplate()
函数只能进行单对象模板匹配,如果需要进行多对象模板匹配,可以在匹配结果中进行进一步处理,例如使用非极大值抑制来消除重叠的匹配结果。
使用不同的匹配方法或得到不一样的匹配结果:
cv2.TM_CCOEFF:
cv2.TM_CCOEFF_NORMED:
cv2.TM_CCORR:
cv2.TM_CCORR_NORMED:
cv2.TM_SQDIFF:
cv2.TM_SQDIFF_NORMED:
多对象模板匹配是在一幅图像中寻找多个目标对象的位置。在前面的讲解中,我们在图片中搜素梅西的脸而且梅西只在图片中出现了一次,算法很好地完成了匹配。但是,假如你的目标对象在图像中出现了很多次要怎么办呢?函数cv2.imMaxLoc() 只会给出最大值和最小值。此时,我们就需要使用阈值了。在下面的例子中我们要在经典的游戏Mario 的一张截屏图片中找到其中的硬币。
import cv2
import numpy as np
# 加载目标图像和模板图像
target_img = cv2.imread('target.jpg')
template_img = cv2.imread('template.jpg')
# 获取目标图像和模板图像的宽高
target_h, target_w = target_img.shape[:2]
template_h, template_w = template_img.shape[:2]
# 使用平方差匹配算法,也可以转成灰度图像进行比对
result = cv2.matchTemplate(target_img, template_img, cv2.TM_SQDIFF)
# 设置匹配阈值
threshold = 0.9
# 找到匹配结果中超过阈值的位置
locations = np.where(result <= threshold)
locations = list(zip(*locations[::-1]))
# 在目标图像上绘制矩形框
for loc in locations:
top_left = loc
bottom_right = (top_left[0] + template_w, top_left[1] + template_h)
cv2.rectangle(target_img, top_left, bottom_right, (0, 255, 0), 2)
# 显示结果图像
cv2.imshow('Result', target_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
在上述代码中,我们首先加载了目标图像和模板图像,然后使用cv2.matchTemplate()
函数进行模板匹配,得到匹配结果。然后,我们设置了一个匹配阈值,只有匹配结果低于该阈值的位置才会被认为是匹配的位置。最后,我们在目标图像上绘制矩形框来表示匹配位置。需要注意的是,多对象模板匹配可能存在重叠的情况,因此在实际应用中,可能需要进行进一步的处理来区分不同的目标对象。
效果如下: