在传统的图像算法领域,模板匹配作为一种目标检测的算法有着自己的适用空间。opencv实现了模板检测的函数:
result = cv2.matchTemplate(image, template, cv2.TM_CCOEFF)
image为待检测图像,template为模板图像,cv2.TM_CCOEFF为匹配检测的方法
matchTemplate()操作相当于template对image步长为1的卷积,返回值result为二维矩阵存储着每一块区域的匹配度大小为(伪代码):
result.cols = image.cols - template.cols + 1
result.rows = image.rows - template.rows + 1
但是matchTemplate()只能检测和模板图像大小一样的目标,对于不同大小的目标,或者稍有差异的目标检测不行。
针对这样的情况,通过对模板图像和待检测图像提取轮廓图像(减少干扰),改变待检测图像的大小来实现多尺度的模板匹配算法。
#建议用最小的目标来充当模板,再放大可以出去很多噪音(博主(如下代码)就是这么做的)
template = cv2.imread("./asset/object/yourImage.jpg")
h1, w1 = template.shape[:2]
template = cv2.resize(template, (h1 * 3, w1 * 3))
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
template = cv2.Canny(template, 100, 200)
(tH, tW) = template.shape[:2]
# 循环检测指定文件夹内所有bmp图片 改为自己图像存放的路径 读取文件夹下所以jpg文件
for imagePath in glob.glob("./asset/" + "/*.jpg"):
# 加载图像,转为灰度图
image = cv2.imread(imagePath)
image2 = copy.deepcopy(image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 保存最大
found = None
# 循环改变被检测图像的大小 以适应多尺度的模板检测
for scale in np.linspace(3.0, 0.0, 100):
# 改变被检测图像大小,记录比例
# resized = imutils.resize(gray, width=int(gray.shape[1] * scale))
(H, W) = gray.shape[:2]
resized = cv2.resize(gray, (int(W*scale), int(H*scale)))
r = gray.shape[1] / float(resized.shape[1])
# 如果图像小于模板图像 就应当停止
if resized.shape[0] < tH or resized.shape[1] < tW:
break
# 获得被检测图像边缘信息 与模板进行匹配
edged = cv2.Canny(resized, 100, 200)
result = cv2.matchTemplate(edged, template, cv2.TM_CCOEFF)
# print(f'result,{result.shape}')
# 获取最大值 以及对应坐标
(_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)
# 与之前的结果比较
if found is None or maxVal > found[0]:
found = (maxVal, maxLoc, r)
# 依据比例r确定真实被检测图像中模板位置的左上角坐标以及大小
(_, maxLoc, r) = found
(startX, startY) = (int(maxLoc[0] * r * 1), int(maxLoc[1] * r * 1))
(endX, endY) = (int((maxLoc[0] + tW) * r * 1), int((maxLoc[1] + tH) * r * 1))
cv2.rectangle(image2, (startX, startY), (endX, endY), (0, 0, 255), 2)
cv2.imshow("image2", image2)
cv2.waitKey(0)