杰瑞科技汇

OpenCV Python模板匹配怎么用?

核心函数

OpenCV 提供了 cv2.matchTemplate() 函数来实现模板匹配。

OpenCV Python模板匹配怎么用?-图1
(图片来源网络,侵删)

语法:

result = cv2.matchTemplate(image, templ, method, mask=None)

参数说明:

  • image: 源图像,通常是较大的图像。
  • templ: 模板图像,要在源图像中查找的小图像。
  • method: 匹配方法,这是最重要的参数,它决定了如何计算相似度,不同的方法适用于不同的场景。
  • mask (可选): 模板的掩码,如果模板图像有透明背景或不规则形状,可以使用掩码来指定只匹配模板的特定部分,默认为 None

返回值:

  • result: 一个与源图像大小相同的图像,但类型为 float32,这个图像的每个像素值表示模板在该位置匹配的“响应值”或“相似度分数”,响应值越高(或越低,取决于方法),表示匹配越好。

匹配方法

OpenCV 提供了多种匹配方法,它们的主要区别在于如何计算相似度,最常用的有 6 种:

OpenCV Python模板匹配怎么用?-图2
(图片来源网络,侵删)
方法 (Method) 全称 描述 特点
TM_SQDIFF Square Difference 平方差匹配 值越小,匹配越好,完全匹配时为 0。
TM_CCORR Cross Correlation 相关性匹配 值越大,匹配越好,完全匹配时为最大值。
TM_CCOEFF Correlation Coefficient 相关系数匹配 值越大,匹配越好,完全匹配时为 1。
TM_SQDIFF_NORMED Normalized Square Difference 归一化平方差匹配 值越小,匹配越好,范围在 [0, 1],0 为完全匹配。
TM_CCORR_NORMED Normalized Cross Correlation 归一化相关性匹配 值越大,匹配越好,范围在 [0, 1],1 为完全匹配。
TM_CCOEFF_NORMED Normalized Correlation Coefficient 归一化相关系数匹配 值越大,匹配越好,范围在 [-1, 1],1 为完全匹配。

如何选择?

  • 推荐使用归一化方法 (_NORMED),因为它们对光照变化不敏感,结果更可靠。
    • TM_SQDIFF_NORMEDTM_CCORR_NORMED 是最常用的两个。
  • TM_SQDIFFTM_CCORR 是非归一化的,容易受到图像对比度的影响,一般不推荐。

如何定位匹配位置

cv2.matchTemplate() 返回的是一个结果矩阵,我们需要在这个矩阵中找到最大值或最小值的位置,这对应了源图像中模板的最佳匹配位置。

OpenCV 提供了 cv2.minMaxLoc() 函数来方便地找到矩阵中的最小值和最大值及其位置。

语法:

OpenCV Python模板匹配怎么用?-图3
(图片来源网络,侵删)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

返回值:

  • min_val: 结果矩阵中的最小值。
  • max_val: 结果矩阵中的最大值。
  • min_loc: 最小值的位置 (x, y)。
  • max_loc: 最大值的位置 (x, y)。

如何使用 minMaxLoc

  • 如果使用 TM_SQDIFFTM_SQDIFF_NORMED(值越小越好),min_loc 就是最佳匹配位置。
  • 如果使用其他所有方法(值越大越好),max_loc 就是最佳匹配位置。

完整代码示例

下面是一个完整的示例,演示如何使用模板匹配在一张大图中找到小图的位置。

import cv2
import numpy as np
import matplotlib.pyplot as plt
# 1. 读取源图像和模板图像
# 注意:OpenCV 默认以 BGR 格式读取图像
source_img = cv2.imread('source.jpg')
template_img = cv2.imread('template.jpg')
# 如果图像或模板未找到,则退出
if source_img is None or template_img is None:
    print("Error: Could not read image(s). Check file paths.")
    exit()
# 2. 获取模板图像的宽度和高度
# 这些值用于在源图像上绘制矩形框
h, w = template_img.shape[:2]
# 3. 执行模板匹配
# 使用归一化的平方差方法,值越小越好
method = cv2.TM_SQDIFF_NORMED
result = cv2.matchTemplate(source_img, template_img, method)
# 4. 在结果矩阵中找到最佳匹配位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
# 5. 根据匹配方法确定最佳匹配坐标
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)
# 6. 在源图像上绘制矩形框
# 使用绿色 (0, 255, 0) 线条,线宽为 2
matched_img = source_img.copy()
cv2.rectangle(matched_img, top_left, bottom_right, (0, 255, 0), 2)
# 7. 显示结果
# 使用 matplotlib 显示图像,因为它能更好地处理 BGR 到 RGB 的转换
plt.figure(figsize=(15, 5))
# 显示源图像
plt.subplot(131), plt.imshow(cv2.cvtColor(source_img, cv2.COLOR_BGR2RGB))'Source Image'), plt.axis('off')
# 显示模板图像
plt.subplot(132), plt.imshow(cv2.cvtColor(template_img, cv2.COLOR_BGR2RGB))'Template Image'), plt.axis('off')
# 显示匹配结果
plt.subplot(133), plt.imshow(cv2.cvtColor(matched_img, cv2.COLOR_BGR2RGB))'Match Result'), plt.axis('off')
plt.show()
# 打印匹配结果信息
print(f"Best match top-left corner: {top_left}")
print(f"Match confidence (for TM_SQDIFF_NORMED, lower is better): {min_val:.4f}")

代码解释与进阶技巧

1 多个对象匹配

上面的代码只找到了一个最佳匹配,如果源图像中有多个与模板相似的物体怎么办?

我们可以设置一个阈值,然后找出所有响应值低于(或高于,取决于方法)该阈值的点。

# 假设我们已经执行了 matchTemplate 并得到了 result
# method = cv2.TM_CCOEFF_NORMED # 使用归一化相关系数,值越大越好
# 设定一个阈值
threshold = 0.8
# 找到所有大于阈值的匹配位置
loc = np.where(result >= threshold)
# 遍历所有找到的位置
for pt in zip(*loc[::-1]): # *loc[::-1] 是为了将坐标 (y,x) 转换为 (x,y)
    # 绘制矩形框
    cv2.rectangle(source_img, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)
# 显示结果
plt.imshow(cv2.cvtColor(source_img, cv2.COLOR_BGR2RGB))'Multiple Objects Matched')
plt.axis('off')
plt.show()

2 模板匹配的局限性

模板匹配虽然简单,但也有明显的缺点:

  1. 旋转和缩放敏感:标准模板匹配无法处理模板在源图像中发生旋转或缩放的情况,如果物体旋转了,就匹配不到了。
  2. 光照敏感:虽然归一化方法有所改善,但剧烈的光照变化仍然会影响匹配效果。
  3. 背景干扰:如果模板的背景比较复杂,或者源图像中模板的背景发生了变化,匹配效果会很差。

3 替代方案

当模板匹配效果不佳时,可以考虑更强大的目标检测方法:

  • 特征点检测 (如 SIFT, SURF, ORB):这些方法检测图像中的关键点和描述符,然后通过匹配描述符来找到物体,对旋转和缩放有较好的鲁棒性。
  • 深度学习方法 (如 YOLO, SSD, Faster R-CNN):对于现代应用,尤其是复杂场景,基于深度学习的目标检测模型是更准确、更可靠的选择。

希望这个详细的解释能帮助你理解和使用 OpenCV 的模板匹配功能!

分享:
扫描分享到社交APP
上一篇
下一篇