Opencv 学习笔记:多模板匹配(多目标定位 + 重复框过滤)

多模板匹配是单模板匹配的扩展,可在图像中定位多个相同模板目标,核心解决 "单目标匹配→多目标筛选→重复框过滤" 问题。本文修复原代码核心问题,演示完整的多模板匹配实现,新手可直接复用。

核心代码实现

python 复制代码
import cv2 as cv
import numpy as np

# 1. 读取模板和待匹配图像(增加空值校验)
tpl = cv.imread('.\image\19.bmp')  # 模板图像
target = cv.imread('.\image\20.bmp')  # 待匹配图像
if tpl is None or target is None:
    print('图像读取失败,请检查路径!')
    exit()

# 显示模板和待匹配图像
cv.namedWindow('tpl', cv.WINDOW_NORMAL)
cv.resizeWindow('tpl', 600, 600)
cv.imshow('tpl', tpl)
cv.imshow('target', target)

# 2. 定义匹配算法(优先归一化相关系数,鲁棒性最强)
TM_SQDIFF = cv.TM_SQDIFF          # 平方差:0最好
TM_SQDIFF_NORMED = cv.TM_SQDIFF_NORMED
TM_CCORR = cv.TM_CCORR            # 相关性:1最好
TM_CCORR_NORMED = cv.TM_CCORR_NORMED
TM_CCOEFF = cv.TM_CCOEFF          # 相关系数:1最好
TM_CCOEFF_NORMED = cv.TM_CCOEFF_NORMED  # 推荐使用

# 3. 执行多模板匹配(关键:待匹配图在前,模板在后!)
result = cv.matchTemplate(target, tpl, TM_CCOEFF_NORMED)
# 归一化匹配结果,统一数值范围[0,1]
cv.normalize(result, result, 0, 1, cv.NORM_MINMAX, -1)

# 4. 筛选高匹配度位置(阈值0.8,可根据实际场景调整)
threshold = 0.8
# 获取所有匹配度≥阈值的坐标(np.where返回(行,列),需反转为(列,行))
locs = np.where(result >= threshold)
# 转换坐标格式:(x,y)
match_locs = list(zip(*locs[::-1]))

# 5. 重复框过滤(避免相邻重复标注)
filtered_locs = []
temp_loc = None
tpl_h, tpl_w = tpl.shape[:2]  # 模板的宽高(匹配框尺寸)
gap_threshold = 110  # 重复框判定阈值(像素)

for loc in match_locs:
    # 首次匹配或当前框与上一个框间距≥阈值,保留
    if temp_loc is None or (abs(loc[0] - temp_loc[0]) > gap_threshold) or (abs(loc[1] - temp_loc[1]) > gap_threshold):
        filtered_locs.append(loc)
        temp_loc = loc

# 6. 绘制所有匹配框(在待匹配图像上标注)
draw_img = target.copy()
for (x, y) in filtered_locs:
    # 匹配框右下角坐标:x+tpl_w, y+tpl_h
    cv.rectangle(draw_img, (x, y), (x + tpl_w, y + tpl_h), (0, 0, 255), 3)

# 7. 显示匹配结果
cv.namedWindow('img', cv.WINDOW_NORMAL)
cv.resizeWindow('img', 600, 600)
cv.imshow('img', draw_img)

cv.waitKeyEx(0)
cv.destroyAllWindows()

关键知识点解析

1. 多模板匹配核心流程

步骤 核心操作 作用说明
匹配计算 cv.matchTemplate(target, tpl, 算法) 生成全图匹配度矩阵
阈值筛选 np.where(result >= 0.8) 过滤低匹配度位置,只保留高置信度目标
坐标转换 zip(*locs[::-1]) 将 np.where 返回的 (行,列) 转为图像 (列,行) 坐标
重复过滤 间距判断abs(x1-x2) > 110 避免同一目标被多次标注
绘制标注 cv.rectangle() 可视化所有匹配目标

2. 核心避坑点

  • 参数顺序 :原代码matchTemplate(tpl, target)顺序颠倒,正确应为(待匹配图, 模板),否则匹配结果完全错误;
  • 匹配框尺寸 :框的宽高需取模板图像tpl_w/tpl_h,而非 target,原代码用 target 尺寸会导致框大小错误;
  • 重复过滤逻辑 :原代码temp_loc[0]+110 < loc[0]仅判断单方向,改为abs()绝对值判断,避免漏过滤;
  • 绘图载体 :在target.copy()上绘图,避免修改原始图像。

3. 优化技巧

  • 阈值调优:阈值 0.8 是经验值,目标清晰时可提高(如 0.9),目标模糊时可降低(如 0.7);
  • 批量模板:若需匹配多个不同模板,可循环加载模板并执行匹配,最后合并结果;
  • 效率提升:对大图像,可先缩放后匹配,再还原坐标,减少计算量;
  • 更优去重:复杂场景可改用非极大值抑制(NMS)算法,替代简单间距判断。

总结

  1. 多模板匹配核心是阈值筛选 + 重复框过滤,区别于单模板匹配的 "找极值";
  2. matchTemplate参数顺序必须是(待匹配图, 模板),匹配框尺寸取模板宽高;
  3. 重复框过滤需用绝对值间距判断,避免单方向判断导致漏过滤。
相关推荐
世人万千丶9 小时前
参数管理_Flutter在鸿蒙平台路由参数最佳实践
学习·flutter·华为·harmonyos·鸿蒙
深度研习笔记9 小时前
OpenCV工业视觉实战11|多线程解耦+视频流稳流+推理加速,彻底解决卡顿阻塞,实现毫秒级工业实时检测
人工智能·opencv·计算机视觉
遇乐的果园11 小时前
前端学习笔记-vue加载渲染优化
前端·笔记·学习
遇乐的果园13 小时前
前端学习笔记-vue状态管理优化
前端·笔记·学习
从零开始的代码生活_13 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法
可乐奶茶sky14 小时前
AI Agent 学习
人工智能·学习
摇滚侠14 小时前
Java 全栈开发实战教程 课程笔记 29-33
笔记
茯苓gao14 小时前
嵌入式开发笔记:EtherCAT协议从硬件到软件完整配置指南——从零搭建一套EtherCAT通信系统
笔记·嵌入式硬件·学习
whyTeaFo15 小时前
GAMES101: Lecture 9: Shading 3(Texture Mapping cont.) ppt笔记
笔记
RD_daoyi16 小时前
外链权重暴跌至13%,品牌提及反超传统链接——2026年不做Digital PR,你的独立站等于隐形
运维·网络·学习·机器学习·搜索引擎