1. 模板匹配介绍

模板匹配(Template Matching)是计算机视觉和图像处理中一种常用的技术,用于在较大图像中定位与给定模板图像最相似的区域。它是一种基于像素比较的方法,广泛应用于:

  • 目标检测
  • 物体识别
  • 工业检测
  • 医学图像分析
  • 视频监控等领域

2. 模板匹配原理

基本思想

模板匹配的基本思想是:在源图像上滑动模板图像,计算模板与源图像对应区域的相似度,找到相似度最高的位置即为匹配结果。

数学表示

对于源图像I(大小为W×H)和模板T(大小为w×h),在源图像上的每个位置(x,y)计算相似度:

互相关公式: R(x,y) = \sum_{x'=0}^{w-1}\sum_{y'=0}^{h-1} [T(x',y') - I(x+x', y+y')]^2

其中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()

运行效果

模板匹配虽然简单,但在特定条件下(如工业检测中的固定场景)仍然非常有效且实用。

这种基于滑动窗口的相识度匹配是很多计算机视觉的基础,从中我们也能慢慢的步入目标检测的大门

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐