008 OpenCV matchTemplate 模板匹配
目录
一、环境
二、模板匹配算法原理
三、代码演示
一、环境
本文使用环境为:
- Windows10
- Python 3.9.17
- opencv-python 4.8.0.74
二、模板匹配算法原理
cv.matchTemplate
是OpenCV库中的一个函数,用于在图像中查找与模板匹配的特征。它的主要应用场景是在图像处理、计算机视觉和模式识别等领域。
算法原理: cv.matchTemplate
函数通过计算输入图像与模板图像之间的相似度来找到最佳匹配位置。它使用滑动窗口的方法在输入图像上移动模板图像,并计算每个窗口内的像素值差异。然后,根据所选的匹配方法(如平方差、归一化平方差、相关系数等),对差异进行加权求和,得到一个匹配得分矩阵。最后,函数返回得分矩阵中的最大值及其位置,作为最佳匹配位置。
函数API:
retval, result = cv2.matchTemplate(image, templ, method, mask)
参数说明:
image
:输入图像,通常是一个灰度图像。templ
:模板图像,可以是灰度图像或彩色图像。method
:匹配方法,常用的有:cv2.TM_SQDIFF
:平方差匹配法,计算结果越小表示匹配程度越高。cv2.TM_SQDIFF_NORMED
:归一化平方差匹配法,计算结果越接近0表示匹配程度越高。cv2.TM_CCORR
:相关系数匹配法,计算结果越接近1表示匹配程度越高。cv2.TM_CCORR_NORMED
:归一化相关系数匹配法,计算结果越接近1表示匹配程度越高。cv2.TM_CCOEFF
:相关系数匹配法,计算结果越接近1表示匹配程度越高。cv2.TM_CCOEFF_NORMED
:归一化相关系数匹配法,计算结果越接近1表示匹配程度越高。
- mask:可选参数,mask是一个二值图,作用于参数temp1,有效区域则参与模板匹配计算
返回值说明:
result
:匹配结果矩阵,每个元素表示对应位置的匹配程度。minVal, maxVal, minLoc, maxLoc
:最佳匹配位置的最小值、最大值、最小值位置和最大值位置。
下面是对 cv.matchTemplate()
算法的简单解释:
- 预处理:首先,将输入图像和模板图像转换为灰度图像。这是因为
cv.matchTemplate()
算法只支持灰度图像。 - 滑动模板:然后,算法会在输入图像上滑动模板。对于每个位置(从左到右、从上到下呗),都会计算一个匹配分数。这个分数取决于当前位置的图像和模板的相似性。
- 计算匹配分数:根据选择的匹配方法,计算当前位置的匹配分数。例如,如果选择的是归一化相关系数方法,那么算法会计算输入图像和模板在当前位置的相关系数。其他方法,如归一化相关、平方差等,会有不同的计算方式。
- 找到最匹配的位置:在所有位置中,算法会找到匹配分数最高的位置。这个位置就是最匹配的位置。
- 返回结果:最后,函数会返回一个包含所有匹配区域信息的结构。这个结构包含了每个匹配区域的坐标、匹配分数等信息。
需要注意的是,由于滑动窗口的限制,如果模板和图像的某些区域不匹配,这些区域将不会被计入匹配分数。这是通过使用掩码(mask)参数实现的。掩码是一个与模板大小相同的二维数组,值可以是0或1。在掩码中为1的位置将被计入匹配分数,为0的位置则不会被计入。
总的来说,cv.matchTemplate()
是一个强大的工具,可以用于在图像中查找和模板最匹配的区域。它广泛应用于图像处理、计算机视觉和模式识别等领域。
三、代码演示
代码中需要的三张图,这里给出来,lena_tmpl.jpg,以下是原图:
tmpl.png,以下是模板图,意思是:在原图中找到与其相似的区域,用矩形画出来。
mask.png,必须与tmp1.png尺寸相同,是一个二值图,用于表示:模板计算过程中,模板图中哪些区域用于模板匹配。
from __future__ import print_function
import sys
import cv2 as cv
# 全局变量
use_mask = False
img = None
templ = None
mask = None
image_window = "Source Image"
result_window = "Result window"
match_method = 0
max_Trackbar = 5
def main():
# 读取三张图
global img
global templ
img = cv.imread('data/lena_tmpl.jpg', cv.IMREAD_COLOR) # 图片1
templ = cv.imread('data/tmpl.png', cv.IMREAD_COLOR) # 图片2
global use_mask
use_mask = True
global mask
mask = cv.imread('data/mask.png', cv.IMREAD_COLOR ) # 图片3
if ((img is None) or (templ is None) or (use_mask and (mask is None))):
print('Can\'t read one of the images')
return -1
cv.namedWindow( image_window, cv.WINDOW_AUTOSIZE )
cv.namedWindow( result_window, cv.WINDOW_AUTOSIZE )
# 创建滑条
trackbar_label = 'Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED'
cv.createTrackbar( trackbar_label, image_window, match_method, max_Trackbar, MatchingMethod )
# 执行模板匹配
MatchingMethod(match_method)
cv.waitKey(0)
return 0
def MatchingMethod(param):
global match_method
match_method = param
img_display = img.copy()
# 模板匹配
method_accepts_mask = (cv.TM_SQDIFF == match_method or match_method == cv.TM_CCORR_NORMED)
if (use_mask and method_accepts_mask):
result = cv.matchTemplate(img, templ, match_method, None, mask)
else:
result = cv.matchTemplate(img, templ, match_method)
# 将结果进行归一化到[0, 1]
cv.normalize( result, result, 0, 1, cv.NORM_MINMAX, -1 )
# 找到最佳匹配
_minVal, _maxVal, minLoc, maxLoc = cv.minMaxLoc(result, None)
# 得到的匹配位置,即:一个矩形框
if (match_method == cv.TM_SQDIFF or match_method == cv.TM_SQDIFF_NORMED):
matchLoc = minLoc
else:
matchLoc = maxLoc
# 可视化
cv.rectangle(img_display, matchLoc, (matchLoc[0] + templ.shape[0], matchLoc[1] + templ.shape[1]), (0,255,0), 2, 8, 0 )
cv.rectangle(result, matchLoc, (matchLoc[0] + templ.shape[0], matchLoc[1] + templ.shape[1]), (0,0,255), 2, 8, 0 )
cv.imshow(image_window, img_display)
cv.imshow(result_window, result)
pass
if __name__ == "__main__":
main()
以下是不同算法运行效果,哪些算法吊,一眼就能看出来,自己可以玩一玩哈。
\n 0: SQDIFF
\n 1: SQDIFF
\n 2: TM CCORR
\n 3: TM CCORR
\n 4: TM COEFF
\n 5: TM COEFF