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

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. 总结

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

相关文章:

  • 【PyTorch】训练时跟OOM相关的提示信息
  • 传导发射测试(CE)和传导骚扰抗扰度测试(CS)
  • Unity3D仿星露谷物语开发36之锄地动画2
  • 【C++】类和对象之日期类的实现(构造、运算符重载)
  • 机器学习中的“三态模型“:过拟合、欠拟合和刚刚好
  • 在FVM(有限体积法)的CFD仿真中,AI和机器学习的应用
  • 关于进程状态
  • 计算机组成原理笔记(十七)——4.2定点加减运算
  • docker配置skywalking 监控springcloud应用
  • Laravel-vite+vue开发前端模板
  • MIT6.S081-lab4
  • 如何在 Ubuntu 上安装 Apache CouchDB ?
  • 【数据结构和算法】1. 数据结构和算法简介、二分搜索
  • Apache Parquet 文件组织结构
  • MACOS 中聚焦使用技巧
  • 医药采购系统平台第10天02:按药品分类的统计按供货商统计按医院统计统计数据的导出DWR的配置和应用
  • 通过 WebSocket 接收和播放 WSS 协议视频流
  • AES (高级加密标准)
  • 大模型在胆管结石(无胆管炎或胆囊炎)预测及治疗方案制定中的应用研究
  • OpenCV 边缘检测(Edge Detection)cv2.Canny
  • 国安部:机关工作人员用软件扫描涉密文件备份网盘致重大泄密
  • 重点并不在于设计更聪明的机器,而在于开发宇宙技术的多样性
  • 明查|俄罗斯征兵部门突袭澡堂抓捕壮丁?
  • C909飞机开启越南商业运营
  • 张宝亮任山东临沂市委书记
  • 为博眼球竟编造一女孩被活埋,公安机关公布10起谣言案件