Python OpenCV 模板匹配

什么是模板匹配?

模板匹配是一项在一幅图像中寻找与另一幅模板图像最匹配(相似)部分的技术。

如何实现模板匹配?

我们需要2幅图像:原图像和模板,我们希望在原图像中找到一块和模板图像最匹配的区域。

为了确定匹配区域,我们在原图像上滑动模板图像和原图像进行比较:

模板图像块一次移动一个像素 (从左往右,从上往下),在每一个位置都进行一次度量计算它与这个位置的匹配程度 (或者说模板图像和原图像的特定区域有多么相似),这一过程与CNN中的卷积操作类似,模板图像相当于卷积核。

对于模板图像 T 覆盖在原图像 I 上的每个位置,把计算出的度量值(匹配程度)保存到结果图像矩阵 (R) 中,在 R 中的每个位置都包含匹配度量值,并且 R 的大小为 - + 1 。

计算出 R 后,我们使用OpenCV函数 minMaxLoc(查找数组中最小和最大元素值及其位置)来定位在矩阵 R 中的最大值点 (或者最小值,根据函数输入的匹配参数) 。

OpenCV中支持哪些匹配算法?

1.平方差匹配 method=CV_TM_SQDIFF

这类方法利用平方差来进行匹配,最好匹配为0,匹配越差,匹配值越大。

                                                       R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2

2.标准平方差匹配 method=CV_TM_SQDIFF_NORMED

                                                      R(x,y)= \frac{\sum_{x',y'} (T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}}

3.相关匹配 method=CV_TM_CCORR

这类方法采用模板和图像间的乘法操作,所以较大的数表示匹配程度较高,0标识最坏的匹配效果。

                                                      R(x,y)= \sum _{x',y'} (T(x',y')  \cdot I(x+x',y+y'))

4.标准相关匹配 method=CV_TM_CCORR_NORMED

                                                      R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I'(x+x',y+y'))}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}}

5.相关匹配 method=CV_TM_CCOEFF

这类方法将模版对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列)。

                                                      R(x,y)= \sum _{x',y'} (T'(x',y')  \cdot I(x+x',y+y'))

其中

                                                      \begin{array}{l} T'(x',y')=T(x',y') - 1/(w  \cdot h)  \cdot \sum _{x'',y''} T(x'',y'') \\ I'(x+x',y+y')=I(x+x',y+y') - 1/(w  \cdot h)  \cdot \sum _{x'',y''} I(x+x'',y+y'') \end{array}

6.标准相关匹配 method=CV_TM_CCOEFF_NORMED

                                                      R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} }

一般来说,随着从简单的测量(平方差)到更复杂的测量(相关系数),能获得越来越准确的匹配(也意味着越来越大的计算代价),最好的办法是对所有这些设置多做一些测试实验,以便为自己的应用选择同时兼顾速度和精度的最佳方案。 

代码

def templateMacthing(src, template, method):
	result = cv2.matchTemplate(src, template, method)
	min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
	location = [0, 0]
	if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
		location = min_loc
	else:
		location = max_loc
	return location
def main():
	src = cv2.imread('src.png', 1) 
	template = cv2.imread('template .png', 1)
	methods = [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED, cv2.TM_CCORR, cv2.TM_CCORR_NORMED, cv2.TM_CCOEFF, cv2.TM_CCOEFF_NORMED]
	locations = []
	for method in methods:
		locations.append(templateMacthing(src, template, method))
	print(locations)

结果

准备一张原图像:

一张模板图像:

运行之后6种方法返回的最匹配坐标值为:[(110, 106), (110, 106), (111, 148), (110, 106), (110, 106), (110, 106)]

可以看出使用CCORR方法的结果和其他结果不一样,那么它是一个错误的匹配。下面看一下其他匹配结果:

cv2.rectangle(src, (location[0],location[1]), (location[0]+width,location[1]+height), (0,0,255),3)
cv2.imshow('result', src)
cv2.waitKey(0)

猜你喜欢

转载自blog.csdn.net/a906958671/article/details/89551856