当前位置: 首页 > ds >正文

OpenCV 模板与多个对象匹配方法详解(继OpenCV 模板匹配方法详解)

文章目录

  • 前言
  • 1.导入库
  • 2.图片预处理
  • 3.输出模板图片的宽和高
  • 4.模板匹配
  • 5.获取匹配结果中所有符合阈值的点的坐标
    • 5.1 threshold = 0.9:
    • 5.2 loc = np.where(res >= threshold):
  • 6.遍历所有匹配点
    • 6.1 loc 的结构回顾
    • 6.2 loc[::-1] 的作用
      • 6.2.1 为什么需要反转?
    • 6.3 zip(*loc[::-1]) 的作用
  • 7.画出模板匹配矩形框
    • 7.1 功能
    • 7.2 参数详解
    • 7.3 关键细节
    • 7.4 常见问题
  • 8.运行结果
  • 9. 总结

前言

上文《OpenCV 模板匹配方法详解》我们详细介绍了模板匹配这一方法,本文我们来介绍一下模板与多个对象匹配的方法。

其中有很多的函数需要我们来详细介绍,接下来我们直接看代码讲解:

1.导入库

import cv2
import numpy as np
  • 导入opencv库和numpy库

2.图片预处理

img_rgb = cv2.imread("image.jpg")
img_gray = cv2.cvtColor(img_rgb,cv2.COLOR_BGR2GRAY)
template = cv2.imread("tem.jpg",0)
  • 导入图片,并转化为灰度图
  • 导入的图片如下图所示,左图为匹配图片,右图为模板图片

在这里插入图片描述


3.输出模板图片的宽和高

h,w = template.shape[:2]
  • template.shape:假设 template 是一个 NumPy 数组(通常是图像数据),.shape 属性会返回数组的维度信息。
  • 对于图像:通常返回 (高度, 宽度, 通道数),如果是灰度图则只有 (高度, 宽度)
  • [:2]:切片操作,取前两个元素
  • 例如对于彩色图像 (480, 640, 3),取前两个值得到 (480, 640)
  • h, w = …:元组解包
  • 将前两个值分别赋值给变量 h (height/高度) 和 w (width/宽度)

所以这行代码的作用是:获取模板图像的高度和宽度,分别存入变量 h 和 w 中。


4.模板匹配

# 使用模板匹配方法 cv2.matchTemplate 进行模板匹配
res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)

功能:

  • 模板匹配:在 img_gray(灰度图像)中滑动 template(模板图像),计算每个位置的 相似度,并返回一个 相似度矩阵 res。
  • 匹配方法:cv2.TM_CCOEFF_NORMED 是 归一化相关系数匹配,取值范围 [-1, 1],越接近 1 表示匹配度越高。

返回值 res:

  • res 是一个 二维浮点型数组,大小 = (img_h - template_h + 1, img_w - template_w +1)(因为模板不能超出原图边界)
  • 每个 res[y, x] 表示模板在 (x, y) 处的匹配得分。

5.获取匹配结果中所有符合阈值的点的坐标

# 设定匹配阈值
threshold = 0.9
# 获取匹配结果中所有符合阈值的点的坐标
loc = np.where(res >= threshold) #(符合条件的行,符合条件的列)

5.1 threshold = 0.9:

功能:

  • 设定一个 匹配阈值,只有 res 中 ≥ 0.9 的点才被认为是有效匹配。

调整建议:

  • 阈值越高(如 0.95),匹配越严格,漏检率可能增加。
  • 阈值越低(如 0.8),匹配越宽松,但可能误检。

5.2 loc = np.where(res >= threshold):

功能:

  • 查找所有匹配度 ≥ threshold 的坐标,返回它们的 行列索引。
  • loc 是一个 元组,包含两个数组:
  •  loc[0]:所有匹配点的 Y 坐标(行索引)
    
  •  loc[1]:所有匹配点的 X 坐标(列索引
    

示例
假设 res 如下:

res = [[0.1, 0.3, 0.7],[0.8, 0.95, 0.6],  # (1,1) = 0.95 ≥ 0.9[0.4, 0.9, 0.2]    # (2,1) = 0.9 ≥ 0.9
]

执行 loc = np.where(res >= 0.9) 后:

loc = (array([1, 2]), array([1, 1]))  # 匹配点:(Y=1,X=1), (Y=2,X=1)

注意:loc 是一个元组,格式为 (y_coords, x_coords),所以先返回的是Y值,再返回的是X值!!!


6.遍历所有匹配点

for pt in zip(*loc[::-1]):

这段代码 for pt in zip(*loc[::-1]): 是 模板匹配后处理 的关键部分,用于遍历所有匹配到的目标位置,并调整坐标顺序以适应 OpenCV 的绘图要求。下面详细解析它的作用:

6.1 loc 的结构回顾

在之前的代码中:

loc = np.where(res >= threshold)
  • loc 是一个元组,格式为 (y_coords, x_coords),所以先返回的是Y值,再返回的是X值

6.2 loc[::-1] 的作用

loc[::-1] 的作用loc[::-1] 对元组进行 反向切片,将 (y_coords, x_coords) 变成 (x_coords, y_coords)。
例如:

loc = (array([1, 2]), array([3, 4]))
loc[::-1] = (array([3, 4]), array([1, 2]))  
# 现在顺序是 (x, y)

6.2.1 为什么需要反转?

  • OpenCV 的坐标系统使用 (x, y)(列在前,行在后),而 np.where() 返回的是 (y, x),因此需要交换顺序。

6.3 zip(*loc[::-1]) 的作用

  • *loc[::-1] 解包 元组,相当于
zip(array([3, 4]), array([1, 2]))
  • zip() 将两个数组按元素配对,生成可迭代的 (x, y) 坐标对
for pt in zip(*loc[::-1]):print(pt)  # 输出:(3, 1), (4, 2)

最终效果:
遍历所有匹配点,每次循环的 pt 是一个 (x, y) 坐标元组,可以直接用于 OpenCV 绘图函数(如 cv2.rectangle())。


7.画出模板匹配矩形框

cv2.rectangle(img_rgb,pt,(pt[0] + w,pt[1] + h),(0,0,255),1)

这段代码 cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 1) 是 OpenCV 中用于在图像上绘制矩形的函数,具体含义如下:


7.1 功能

在图像 img_rgb 上,以 pt 为左上角起点,绘制一个 宽度为 w、高度为 h 的红色矩形框,边框粗细为 1 像素


7.2 参数详解

参数含义示例
img_rgb要绘制矩形的目标图像(RGB 格式)从 cv2.imread()读取的图像
pt矩形的 左上角坐标 (x, y)(50, 100) 表示从图像的第 50 列、第 100 行开始
(pt[0] + w, pt[1] + h)矩形的 右下角坐标如果 pt=(50,100),w=30,h=20,则右下角是 (80, 120)
(0, 0, 255)矩形颜色(BGR 格式)(0,0,255)表示纯红色
1矩形边框的粗细(像素)1 表示 1 像素宽,-1表示填充矩形

7.3 关键细节

  1. 坐标顺序

    • OpenCV 使用 (x, y) 坐标,其中:
      • x 是水平方向(列索引,从左到右递增)
      • y 是垂直方向(行索引,从上到下递增)
  2. 颜色格式

    • (0, 0, 255)BGR 格式(不是 RGB),所以这里表示红色。
    • 常见颜色示例:
      • 红色:(0, 0, 255)
      • 绿色:(0, 255, 0)
      • 蓝色:(255, 0, 0)
  3. 矩形尺寸

    • w 和 h通常是模板图像的宽度和高度(通过 template.shape[:2] 获取)。
    • 如果 w 或 h 超出图像边界,OpenCV 会报错。

7.4 常见问题

  1. 为什么矩形颜色不对?

    • 检查颜色是否是 BGR 格式,例如红色应为 (0, 0, 255),而非 RGB 的 (255, 0, 0)。
  2. 如何调整矩形样式?

    • 修改参数:
      • 边框粗细:2 表示更粗的边框,-1 表示填充矩形。
      • 颜色:(255, 0, 0) 是蓝色,(0, 255, 0) 是绿色。

8.运行结果

在这里插入图片描述

9. 总结

到这里本篇博客就结束啦,感谢大家的阅读!最近一直在坚持每天写博客,当作是一个叙说心得的地方,在这个过程中自己通过不断的回顾之前所学习的内容,发现很多细节地方之前都没有注意到,通过再一次的回顾,增添了很多收获,这真的就是“温故而知新”这句话现实化了。最后,希望大家能一直朝着自己理想的方向努力。越努力,越幸运!!!

http://www.xdnf.cn/news/697.html

相关文章:

  • 零基础上手Python数据分析 (19):Matplotlib 高级图表定制 - 精雕细琢,让你的图表脱颖而出!
  • 初级达梦dba的技能水准
  • C++:详解命名空间
  • 清醒思考的艺术
  • 二叉树的顺序结构及实现
  • 【第一天】一月速通python,第一天基本语法
  • ZYNQ笔记(九):定时器中断
  • (done) 吴恩达版提示词工程 1. 引言
  • 软件测试笔记(测试的概念、测试和开发模型介绍、BUG介绍)
  • C语言之机房机位预约系统
  • oracle认证大师ocm学习
  • 学习笔记:黑马程序员JavaWeb开发教程(2025.3.23)
  • 基于Spring AI Alibaba实现MCP协议的SSE实时流式服务深度解析
  • 肖特基二极管详解:原理、作用、应用与选型要点
  • Cribl 对Windows-xml log 进行 -Removing filed-06
  • PySide6 GUI 学习笔记——常用类及控件使用方法(常用类尺寸QSizeF)
  • 常见浏览器 WebDriver 驱动下载
  • PCL库开发入门
  • Kubernetes控制平面组件:调度器Scheduler(一)
  • 基于深度学习的线性预测:创新应用与挑战
  • 探秘STM32如何成为现代科技的隐形引擎
  • 【锂电池SOH估计】SVM支持向量机锂电池健康状态估计,锂电池SOH估计(Matlab完整源码和数据)
  • HTMLCSS实现网页轮播图
  • DB-Day9笔记-用户权限数据库备份事务索引视图
  • BFD协议原理
  • PH热榜 | 2025-04-20
  • 安卓处理登录权限问题
  • 09【所有权·核心】规则与移动 (Move):Rust 内存安全基石详解
  • 2025年4月19日-美团春招笔试题-第一题
  • React 路由入门秘籍:BrowserRouter 的江湖之道