模板匹配(Template Matching)是OpenCV中一种用于在图像中查找与给定模板图像相似区域的方法。
模板匹配是一种在图像中查找目标的方法,它的原理是将一个小的模板图像在原始图像中移动,并计算模板图像与原始图像之间的相似度。在相似度达到一定阈值的情况下,我们就可以认为找到了目标。
在 OpenCV 中,可以使用 cv2.matchTemplate() 函数进行模板匹配。
cv2.matchTemplate(image, templ, method[, result[, mask]]) → result
该函数有四个参数:
源图像:即待匹配的图像。 模板图像:即用来匹配的图像。 匹配方法:用来指定匹配算法,常见的有 6 种,包括: - cv2.TM_CCOEFF //系数匹配 - cv2.TM_CCOEFF_NORMED //归一化系数匹配 - cv2.TM_CCORR //相关匹配 - cv2.TM_CCORR_NORMED ////归一化相关匹配 - cv2.TM_SQDIFF //平方差匹配 - cv2.TM_SQDIFF_NORMED //归一化平方差匹配
在这些匹配方法中,cv2.TM_CCOEFF 和 cv2.TM_CCOEFF_NORMED 方法是最常用的。其中 cv2.TM_CCOEFF 方法会计算源图像和模板图像的相关系数,即两个图像的相似度;而 cv2.TM_CCOEFF_NORMED 方法则是将相关系数进行了归一化,即将相关系数除以源图像和模板图像的标准差的乘积,得到的值在 [-1, 1] 之间,越接近 1 表示匹配度越高。
mask:可选参数,用来指定在源图像和模板图像上进行匹配的区域。
下面让我们来写一个使用 OpenCV 进行模板匹配的项目案例。这个项目的目的是在一张大图中匹配一个小图,并标记出匹配到的位置。
import cv2
import numpy as np
# 加载大图和小图
img = cv2.imread('./images/jpg/football_match01.jpg')
template = cv2.imread('./images/jpg/football_match_dest01.jpg')
# 模板匹配
result = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)
# 找到最大值和最大值的位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
# 如果使用 TM_CCOEFF_NORMED 算法,则最大值即为相似度的值
print('匹配相似度:', max_val)
# 找到匹配位置的左上角和右下角坐标
w, h = template.shape[:2]
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
# 在大图上标记匹配位置
cv2.rectangle(img, top_left, bottom_right, (0, 0, 255), 2)
# 显示结果
cv2.imshow('result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()


多模板匹配实例。实现一个车位识别案例。
import cv2
image = cv2.imread('./images/png/car_park01.png') # 读取原始图像
templs = [] # 模板列表
templs.append(cv2.imread("./images/png/car_template001.png")) # 添加模板图像1
templs.append(cv2.imread("./images/png/car_template002.png")) # 添加模板图像1
templs.append(cv2.imread("./images/png/car_template003.png")) # 添加模板图像1
templs.append(cv2.imread("./images/png/car_template004.png")) # 添加模板图像1
for car in templs: # 遍历所有模板图像
# 按照标准相关系数匹配
results = cv2.matchTemplate(image, car, cv2.TM_CCOEFF_NORMED)
for i in range(len(results)): # 遍历结果数组的行
for j in range(len(results[i])): # 遍历结果数组的列
# print(results[i][j])
if results[i][j] > 0.99: # 如果相关系数大于0.99则认为匹配成功
if 0 < j <= 164:
print("车位编号:", 1)
elif j <= 392:
print("车位编号:", 2)
elif j <= 600:
print("车位编号:", 3)
else:
print("车位编号:", 4)
break
源图片。

模板图片:

识别结果:
车位编号: 4
车位编号: 3
车位编号: 2
车位编号: 1