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. 重复框过滤需用绝对值间距判断,避免单方向判断导致漏过滤。
相关推荐
Xudde.3 小时前
HackMe 靶机渗透测试(Vulnhub Writeup)
笔记·学习·安全·web安全
萌萌的提莫队长3 小时前
Unity相机捕捉,图像识别,抠像+合成
opencv·unity
先途检测认证4 小时前
塑料、硅胶、不锈钢材质,欧盟食品接触的测试项目有什么区别?
笔记·材质
跨知易知识产权4 小时前
美国发明专利和外观专利保护期限分别是多久,起算时间怎么界定?
笔记
wdfk_prog4 小时前
LWIP教程 16:从 MTU 到 `ip4_frag()` / `ip4_reass()`——IPv4 分片、重组、超时与内存压力
运维·服务器·网络·笔记·学习
Source.Liu4 小时前
【A11】拥有者模式平台架构笔记
windows·笔记·架构·rust
Xudde.4 小时前
AI-Web1 靶机渗透测试(Vulnhub Writeup)
笔记·学习·安全·web安全
盛世宏博北京4 小时前
十二防档案库房总线架构设计:恒湿消毒净化一体机 RS485 组网实战笔记
开发语言·笔记·php·恒湿机·档案八防温湿度
zyseo84 小时前
谷歌SEO 站点地图优化实战:sitemap 是索引候选清单的运营工具
网络·数据库·经验分享·笔记·搜索引擎
浅念-4 小时前
动态规划:线性DP——多状态DP与子数组专题笔记
c++·笔记·算法·leetcode·职场和发展·动态规划·力扣