图像匹配技术是计算机视觉领域中用于检测图像中特定区域与预设模板匹配度的高级方法。这种技术能够在不考虑方向或局部亮度变化的情况下,识别出图像中与模板相匹配的部分。在医学图像分析、车辆跟踪、机器人技术以及制造业等对象识别领域中,模板匹配因其不变的特性或创新应用而被广泛使用。
模板匹配方法因其多功能性和简单性而成为对象定位最常用的方法之一。其应用主要受限于计算机的处理能力,因为识别大型和复杂的模板可能会非常耗时。该技术的核心在于在更大的图像中搜索并定位一个模板。目标是发现图像中与提供的模板相匹配的相同部分,基于一个阈值来决定识别模板的好坏。例如,在面部识别中,如果想要检测一个人的眼睛,可以使用一个随机的眼睛图像作为模板,并在人脸图像中搜索匹配。
在这种场景下,即使将阈值设置为50%(0.5),由于“眼睛”在人与人之间的差异很大,眼睛仍然可以被识别出来。工作函数是将模板图像滑过输入图像(类似于2D卷积),将模板图像与输入图像下的图像部分进行比较,并将获得的结果与阈值进行比较。如果结果超过阈值,则将该部分标记为已检测到。
首先,需要定义模板匹配。这是一种在源图像中定位参考图像(或模板图像)的方法。在最基本的形式中,算法逐像素比较模板与源图像的每个区域。这被称为互相关。这个过程的结果是另一个图像,其像素值对应于在该像素位置插入模板图像时与源图像的相似度。
让以一个金属瓶盖的图像为例来看看这是如何工作的。假设对红色金属瓶盖感兴趣。首先,需要加载模板图像:
import cv2
template = cv2.imread(r"template_image_path")
w, h = template.shape[::-1]
在存储模板的宽度和高度到变量w和h之后,初始化一个变量discovered来跟踪图像中最佳匹配区域和比例。使用模板匹配函数在输入源图像中检测模板:
res = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.90
loc = np.where(res >= threshold)
for pt in zip(*loc[::-1]):
cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 1)
显示带有标记模板区域的源图像:
cv2.imshow('Detected the template matching objects', img)
cv2.imshow('Template', template)
cv2.waitKey()
cv2.destroyAllWindows()
可以使用多尺度方法来避免模板和原始图像大小不同造成的问题。多尺度模板匹配方法如下:循环遍历不同尺度的输入图像。使用cv2.matchTemplate应用模板匹配,并跟踪具有最高相关系数的匹配(以及具有最大相关系数区域的x和y坐标)。在遍历所有尺度后,选择具有最高相关系数的区域作为“匹配”区域。
如果模板的尺寸与想要匹配的图像区域的尺寸不匹配,这并不妨碍使用模板匹配。多尺度过程如下:
import cv2
import imutils
import numpy as np
img_rgb = cv2.imread('mainimage.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('template', 0)
w, h = template.shape[::-1]
resize = imutils.resize(img_gray, width=int(img_gray.shape[0]), height=int(img_gray.shape[1]*scale))
if resized.shape[0] < h or resized.shape[1] < w:
break
found = (maxVal, maxLoc, r)
(startX, startY) = (int(maxLoc[0]*r), int(maxLoc[1]*r))
(finalX, finalY) = (int((maxLoc[0]+tw)*r), int(maxLoc[1]+tH)*r)
cv2.rectangle(image, (startX, startY), (finalX, finalY), (255, 0, 255), 2)
cv2.imshow("Image", image)
cv2.waitKey(0)
上述代码的逐步解释如下:首先记录模板的宽度和高度到变量w和r。然后,使用np.linspace函数开始循环遍历图像的多个尺度。这个函数接受三个参数:起始值和结束值以及它们之间的等分切片数量。在这个例子中,将从原始图像大小的100%开始,逐步减少到原始大小的20%,分为20个等分的百分比块。
接下来,将图像调整到当前尺度,并计算前一个宽度与新宽度的比率——稍后将看到,这个比率至关重要。验证提供的图像是否大于模板匹配。如果模板更大,cv2.matchTemplate调用将失败。因此,在这种情况下,只是退出循环。现在可以对缩放后的图像应用模板匹配:
将相关结果传递给cv2.minMaxLoc函数,该函数返回一个4元组,包含最小相关值、最大相关值、最小值的(x, y)坐标和最大值的(x, y)坐标。由于只需要最大值和(x, y)坐标,保存最大值并丢弃最小值。然后,在每个尺度迭代中检查匹配的图像区域。然后,更新discovered变量以跟踪迄今为止发现的最大相关值、最大值的(x, y)坐标以及原始图像宽度与当前放大图像宽度的比率。