模板匹配介绍、原理与实现-动手学深度学习4
摘要: 模板匹配是一种基于像素比较的计算机视觉技术,用于在大图像中定位与模板相似的区域。其核心原理是通过滑动模板计算相似度(如互相关),找到最佳匹配位置。Python中可通过OpenCV实现,常用方法包括归一化平方差(TM_SQDIFF_NORMED)和归一化互相关(TM_CCOEFF_NORMED)。该技术简单高效,但对光照、旋转和尺度变化敏感。改进方法包括多目标匹配结合非极大值抑制(NMS)消
·
1. 模板匹配介绍
模板匹配(Template Matching)是计算机视觉和图像处理中一种常用的技术,用于在较大图像中定位与给定模板图像最相似的区域。它是一种基于像素比较的方法,广泛应用于:
- 目标检测
- 物体识别
- 工业检测
- 医学图像分析
- 视频监控等领域
2. 模板匹配原理
基本思想
模板匹配的基本思想是:在源图像上滑动模板图像,计算模板与源图像对应区域的相似度,找到相似度最高的位置即为匹配结果。
数学表示
对于源图像I(大小为W×H)和模板T(大小为w×h),在源图像上的每个位置(x,y)计算相似度:
互相关公式:
其中x'∈[0,w-1], y'∈[0,h-1]
3. 模板匹配实现
Python实现(使用OpenCV)
# 模版匹配
import cv2
from matplotlib import pyplot as plt
import numpy as np
# 读取图像和模板
img = cv2.imread('lenna.jpg')
templ = cv2.imread('template.png')
# 获取模板的高度、宽度和通道数
height, width, c = templ.shape
# # 模块匹配 使用归一化平方差匹配方法(TM_SQDIFF_NORMED)
# results = cv2.matchTemplate(img, templ, cv2.TM_SQDIFF_NORMED)
results = cv2.matchTemplate(img, templ, cv2.TM_CCOEFF)
# 获取匹配结果中的最小值、最大值、最小值坐标和最大值坐标
minValue, maxValue, minLoc, maxLoc = cv2.minMaxLoc(results)
# 计算匹配结果的中心坐标
resultPoint1 = minLoc
resultPoint2 = (resultPoint1[0] + width, resultPoint1[1] + height)
# 绘制矩形框
cv2.rectangle(img, resultPoint1, resultPoint2, (0, 0, 255), 2)
# 显示结果
while True:
cv2.imshow('Matching Result', img)
key = cv2.waitKey(1) # 每1ms检测一次按键
if key == ord('q'): # 按 'q' 退出
break
cv2.destroyAllWindows()
4. 模板匹配的优缺点
优点
- 实现简单直观
- 计算效率相对较高
- 对小角度旋转和轻微形变有一定鲁棒性
缺点
- 对光照变化敏感
- 对旋转和尺度变化适应性差
- 当目标被遮挡时效果不佳
- 背景复杂时容易产生误匹配
最后匹配失败因为光照变化

5. 改进方法
为了提高模板匹配的鲁棒性,可以采用以下改进方法:
使用归一化平方差匹配方法(TM_SQDIFF_NORMED)
results = cv2.matchTemplate(img, templ, cv2.TM_SQDIFF_NORMED)
结果:

6.多目标模板匹配
待匹配图片image.png:

template2.png文件

特别要注意图片大小,不能过大过小,最好是在imshow的待匹配图片里面截图才是最合适的大小
相关代码:
import cv2
import numpy as np
# 读取图像和模板
img = cv2.imread('image.png')
templ = cv2.imread('template2.png')
# 检查图像是否成功加载
if img is None or templ is None:
print("Error: Could not load one or both images")
exit()
# 打印图像尺寸
print("Image size:", img.shape)
print("Template size:", templ.shape)
if img.shape[0] < templ.shape[0] or img.shape[1] < templ.shape[1]:
print("Error: Template is larger than image")
exit()
# 获取模板的高度和宽度
height, width = templ.shape[:2]
# 使用归一化平方差匹配方法
result = cv2.matchTemplate(img, templ, cv2.TM_CCOEFF_NORMED)
# 设置匹配阈值
threshold = 0.7
# 获取所有大于阈值的匹配位置
locations = np.where(result >= threshold)
locations = list(zip(*locations[::-1])) # 转换为(x,y)坐标列表
# 使用非极大值抑制(NMS)来避免重叠的矩形框
def non_max_suppression(boxes, overlap_thresh=0.5):
if len(boxes) == 0:
return []
# 将边界框坐标转换为float类型
boxes = np.array(boxes, dtype="float")
# 初始化选择的索引列表
pick = []
# 获取边界框的坐标
x1 = boxes[:, 0]
y1 = boxes[:, 1]
x2 = boxes[:, 2]
y2 = boxes[:, 3]
# 计算边界框的面积并排序
area = (x2 - x1 ) * (y2 - y1)
idxs = np.argsort(y2)
# 循环遍历排序后的索引
while len(idxs) > 0:
# 获取最后一个索引并将其添加到选择列表中
last = len(idxs) - 1
i = idxs[last]
pick.append(i)
# 找到当前框与其他框的最大(x,y)坐标
xx1 = np.maximum(x1[i], x1[idxs[:last]])
yy1 = np.maximum(y1[i], y1[idxs[:last]])
xx2 = np.minimum(x2[i], x2[idxs[:last]])
yy2 = np.minimum(y2[i], y2[idxs[:last]])
# 计算重叠区域的宽度和高度
w = np.maximum(0, xx2 - xx1)
h = np.maximum(0, yy2 - yy1 )
# 计算重叠比例
overlap = (w * h) / area[idxs[:last]]
# 删除重叠比例大于阈值的所有索引
idxs = np.delete(idxs, np.concatenate(([last], np.where(overlap > overlap_thresh)[0])))
# 返回选择的边界框
return boxes[pick].astype("int")
# 创建边界框列表
rectangles = []
for loc in locations:
rect = [loc[0], loc[1], loc[0] + width, loc[1] + height]
rectangles.append(rect)
# 应用非极大值抑制
rectangles = non_max_suppression(rectangles)
# 绘制所有匹配的矩形框
for (x1, y1, x2, y2) in rectangles:
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
while True:
cv2.imshow('Multi-Template Matching', img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
# 显示结果
cv2.destroyAllWindows()
运行效果

模板匹配虽然简单,但在特定条件下(如工业检测中的固定场景)仍然非常有效且实用。
这种基于滑动窗口的相识度匹配是很多计算机视觉的基础,从中我们也能慢慢的步入目标检测的大门
更多推荐
所有评论(0)