1. 目标
在本章中,您将学习
- 使用模板匹配查找图像中的对象
- 您将了解这些函数: cv.matchTemplate() , cv.minMaxLoc()
模板匹配是一种在较大图像中搜索和查找模板图像位置的方法。为此,OpenCV 带有一个函数 cv.matchTemplate() 。它只是在输入图像上滑动模板图像(如在 2D 卷积中),并比较模板图像下的模板和输入图像的补丁。在 OpenCV 中实现了几种比较方法。 (您可以查看文档以获取更多详细信息)。它返回一个灰度图像,其中每个像素表示该像素的邻域与模板匹配的程度。
如果输入图像的大小(WxH)且模板图像的大小(wxh),则输出图像的大小为(W-w + 1,H-h + 1)。得到结果后,可以使用 cv.minMaxLoc() 函数查找最大/最小值的位置。将其作为矩形的左上角,取(w,h)作为矩形的宽度和高度。那个矩形是你的模板区域。
如果你使用cv.TM_SQDIFF函数作为比较的方法, 最小值作为匹配值。
2. OpenCV模板匹配
在OpenCV中,模板匹配是一种用于在较大图像中寻找模板图像位置的方法。这种方法基于滑动窗口机制,通过在输入图像上滑动模板图像并在每个位置计算模板与图像子区域的相似度来确定最佳匹配位置。
OpenCV提供了`cv2.matchTemplate`函数来实现模板匹配,并提供了几种不同的匹配方法,例如:
- - **平方差匹配方法** (`cv2.TM_SQDIFF`)
- - **相关性匹配方法** (`cv2.TM_CORR`)
- - **相关性系数匹配方法** (`cv2.TM_CCOEFF`)
每种方法都有其变体,例如归一化的版本(`cv2.TM_SQDIFF_NORMED`, `cv2.TM_CORR_NORMED`, `cv2.TM_CCOEFF_NORMED`)。
以下是使用OpenCV进行模板匹配的基本步骤:
- **读取图像和模板**:首先,你需要读取待搜索的图像和模板图像。
- **选择匹配方法**:选择一个合适的匹配方法。通常,如果模板和图像的亮度相似,可以使用`cv2.TM_CCOEFF`或其归一化版本。
- **执行模板匹配**:使用`cv2.matchTemplate`函数执行模板匹配,它会返回一个灰度图像,其中每个像素表示该位置与模板的匹配程度。
- **找出最佳匹配位置**:使用`cv2.minMaxLoc`函数找出匹配结果中的最小值或最大值(取决于选择的匹配方法),这个位置就是模板在图像中的最佳匹配位置。
- **标记匹配位置**:在图像上绘制一个矩形来标记最佳匹配位置。
在这里,作为一个例子,我们将在梅西的照片中搜索他的面部,因此我创建了一个如下的模板:
我们将尝试所有的比较方法,看看它们的结果如何:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
img2 = img.copy()
template = cv.imread('template.jpg',0)
w, h = template.shape[::-1]
# All the 6 methods for comparison in a list
methods = ['cv.TM_CCOEFF', 'cv.TM_CCOEFF_NORMED', 'cv.TM_CCORR',
'cv.TM_CCORR_NORMED', 'cv.TM_SQDIFF', 'cv.TM_SQDIFF_NORMED']
for meth in methods:
img = img2.copy()
method = eval(meth)
# Apply template Matching
res = cv.matchTemplate(img,template,method)
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
# If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
if method in [cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv.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(meth)
plt.show()
请参阅以下结果:
你可以看到使用 **cv.TM_CCORR**的结果并不像我们预期的那样好。
3. 模板与多个对象匹配
在上一节中,我们搜索了梅西的脸部图像,该图像仅在图中出现一次。假设您正在搜索的对象在图中出现了多次, cv.minMaxLoc() 将不会为你提供所有的匹配点。在这种情况下,我们将使用阈值。所以在这个例子中,我们将使用着名游戏 Mario 的截图,并在其中找到硬币。
结果: