什么是模板匹配?
它是怎么实现的?
-
我们需要2幅图像:
- 原图像 (I): 在这幅图像里,我们希望找到一块和模板匹配的区域
- 模板 (T): 将和原图像比照的图像块
我们的目标是检测最匹配的区域:
-
为了确定匹配区域,我们需要滑动模板图像和原图像进行比较 :
-
通过滑动图像块一次移动一个像素 (从左往右,从上往下)。 在每一个位置,都进行一次计算来度量它与那个位置匹配程度 ,或者说模板和原图像的特定区域的相似度。
-
对于 T 覆盖在 I 上的每个位置,把度量值保存到结果图像矩阵R中。在 R 中的每个位置(x, y)都包含匹配度量值:
上图就是TM_CCORR_NORMED方法处理后的结果图像R ,最白的位置代表最高的匹配。正如您所见,红色椭圆框住的位置很可能是结果图像矩阵中的最大数值,所以这个区域 (以这个点为左上角点,长宽和模板图像一样大小的矩阵) 被认为是匹配的.
-
实际中,我们使用函数minMaxLoc来定位在矩阵 R 中的最大值点 (或者最小值,根据函数输入的匹配参数) .
OpenCV中支持哪些匹配算法?
OpenCV通过函数matchTemplate实现了模板匹配算法。 可用的方法有6个:
- 平方差匹配 method=CV_TM_SQDIFF
这类方法利用平方差来进行匹配,最好匹配为0.匹配越差,匹配值越大.
-
标准平方差匹配 method=CV_TM_SQDIFF_NORMED
-
相关匹配 method=CV_TM_CCORR
这类方法采用模板和图像间的乘法操作,所以较大的数表示匹配程度较高,0标识最坏的匹配效果.
-
标准相关匹配 method=CV_TM_CCORR_NORMED
-
相关匹配 method=CV_TM_CCOEFF
这类方法将模版对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列).
在这里
-
标准相关匹配 method=CV_TM_CCOEFF_NORMED
通常,随着从简单的测量(平方差)到更复杂的测量(相关系数),我们可获得越来越准确的匹配(同时也意味着越来越大的计算代价). 最好的办法是对所有这些设置多做一些测试实验,以便为自己的应用选择同时兼顾速度和精度的最佳方案.
总结
模板匹配是用来在一幅大图中搜寻查找模版图像位置的方法。 OpenCV 为我们提供了函数:cv2.matchTemplate()。和2D卷积一样,它也是用模板图像在输入图像(大图)上滑动,并在每一个位置对模板图像和与其对应的输入图像的子区域进行比较。 OpenCV 提供了几种不同的比较方法。返回的结果是一个灰度图像,每一个像素值表示了此区域与模板的匹配程度。当你得到这幅图之后,就可以使用函数cv2.minMaxLoc() 来找到其中的最小值和最大值的位置了。
下面有一个例子,我们在一幅美女图片中搜索其面部,通过对原图截图得到面部模板:
import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('test.png',0) template = cv2.imread('template.png',0) w, h = template.shape[::-1] method_str = 'cv2.TM_SQDIFF' method = eval(method_str) # Apply template Matching res = cv2.matchTemplate(img, template, method) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]: top_left = min_loc else: top_left = max_loc bottom_right = (top_left[0] + w, top_left[1] + h) cv2.circle(img,top_left, 6, 255, -1) cv2.rectangle(img, top_left, bottom_right, 255, 2) plt.subplot(121),plt.imshow(res,cmap = 'gray') plt.title('Matching Result'), plt.xticks([]), plt.yticks([]) plt.subplot(122),plt.imshow(img,cmap = 'gray') plt.title('Detected Point'), plt.xticks([]), plt.yticks([]) plt.suptitle(method_str, fontsize=18) # Add a centered title to the figure plt.show()
结果如下:
然而使用cv2.matchTemplate()在下图中匹配爱因斯坦的脸时就出现了匹配错误的情况。可能由于图像中人脸众多,如果要准确匹配人脸特征需要使用更高级的方法。
template
- 多对象的模板匹配
假如你的目标对象只在图像中出现了很多次怎么办呢?函数cv.imMaxLoc() 只会给出最大值和最小值。此时,我们就要使用阈值了。在下面的例子中我们要经典游戏Mario的一张截屏图片中找到其中的硬币。
import cv2 import numpy as np from matplotlib import pyplot as plt img_rgb = cv2.imread('mario.jpg') img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY) template = cv2.imread('mario_coin.png',0) w, h = template.shape[::-1] res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED) threshold = 0.8 loc = np.where( res >= threshold) for pt in zip(*loc[::-1]): cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2) cv2.imwrite('res.png',img_rgb)
结果如下:
参考: