计算机视觉之多模板匹配

简介

计算机视觉第一课opencv(四)保姆级教学

之前说过模糊匹配只是对于单个目标进行匹配,今天我们就来学习一下如何对多个目标进行匹配

一、多目标匹配

        对于这个图片我们要匹配下面那个箭头,我们可以发现图中是有两个位置相同的箭头,之前我们说的模糊匹配是寻找匹配值最大的,那两个怎么寻找呢?

1.基本步骤


1.图像准备
        模板图像:需要被匹配的目标图像,通常是一个较小的图像块。
        输入图像:在其中进行搜索以找到与模板图像相似的多个区域的图像。
2.图像预处理
        转换为灰度图像:在进行模板匹配之前,通常需要将输入图像和模板图像转换为灰度图像,因为灰度图像中的像素值仅表示亮度,不受颜色影响,更适合进行匹配。
        降噪和增强:根据需要,可以对图像进行降噪处理以提高匹配准确性,或进行增强处理以突出目标特征。
3.执行模板匹配
        使用模板匹配算法(如OpenCV中的cv2.matchTemplate()函数)在输入图像中搜索与模板图像相似的区域。
模板匹配算法会生成一个结果图像,其中每个像素的值表示该位置与模板图像的匹配程度。
4.定位匹配区域
        使用cv2.minMaxLoc()等函数在结果图像中找到匹配度最高的区域(或多个区域,如果设置了适当的阈值)。
根据匹配位置在原图中绘制矩形框或其他标记,以指示匹配到的目标。
5.处理多个匹配
        如果需要匹配多个目标,并且这些目标在图像中可能以不同的尺寸、方向或旋转角度出现,则可能需要使用更复杂的算法,如尺度不变特征变换(SIFT)、加速稳健特征(SURF)或ORB等。
        对于简单的多目标匹配,可以通过设置较低的匹配阈值来找到多个匹配区域,并分别处理它们。
6.优化和验证
        根据需要调整模板匹配算法的参数(如匹配方法、阈值等),以优化匹配结果。
        对匹配结果进行验证,确保它们确实是所需的目标,并排除误匹配。

# 导入必要的库:cv2用于图像处理,numpy用于数值计算
import cv2
import numpy as np# 读取原始彩色图像(默认读取为BGR格式,而非RGB)
img_rgb = cv2.imread('beijing.jpg')
# 将彩色图像转为灰度图:模板匹配通常在单通道灰度图上进行,减少计算量和干扰
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
# 读取模板图像:flags=0表示以灰度模式读取(直接得到单通道图像)
template = cv2.imread('jiantou.jpg', flags=0)# 获取模板的高和宽:shape返回(高, 宽, 通道数),[:2]取前两个值(高h和宽w)
h, w = template.shape[:2]# 执行模板匹配:在灰度图上滑动模板,计算每个位置的匹配度
# 参数说明:
# - img_gray:待匹配的灰度图像(大图像)
# - template:模板图像(小图像)
# - cv2.TM_CCOEFF_NORMED:匹配方法(归一化相关系数匹配)
# 返回值res:是一个矩阵,每个元素表示模板在对应位置的匹配度(范围[-1,1],1为完美匹配)
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)# 设定匹配阈值:只有匹配度≥0.9的区域才被认为是有效匹配(过滤低匹配度的干扰)
threshold = 0.9# 获取所有符合阈值的匹配点坐标:
# np.where(res >= threshold)返回满足条件的索引,格式为(行坐标数组, 列坐标数组)
# 例如:(array([5, 10]), array([3, 7]))表示有两个匹配点,坐标为(5,3)和(10,7)
loc = np.where(res >= threshold)# 遍历所有匹配点,在原图上绘制矩形框标记
# zip(*loc[::-1])的作用:将坐标从(行,列)转为(列,行)(OpenCV中坐标是(x,y)即列在前,行在后)
for pt in zip(*loc[::-1]):# 绘制矩形:# - img_rgb:要绘制的图像(原始彩色图,方便直观查看)# - pt:矩形左上角坐标(x,y)# - (pt[0]+w, pt[1]+h):矩形右下角坐标(左上角x+模板宽,左上角y+模板高)# - color=(0,0,255):矩形颜色(BGR格式,这里是红色)# - thickness=1:矩形线宽cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), color=(0, 0, 255), thickness=1)# 显示标记后的图像:第一个参数是窗口名称(空字符串表示默认窗口),第二个参数是图像
cv2.imshow('', img_rgb)
# 等待用户按键输入:0表示无限等待(直到按下任意键关闭窗口)
cv2.waitKey(0)

局限性
        只能匹配与模板方向、大小完全一致的目标。如果目标在图像中旋转了(比如箭头方向变了),则无法检测到。那我们就继续探索一下如何去匹配旋转的目标

二、图像旋转

        为了解决上述局限性,需要先掌握如何旋转图像。这部分提供了两种旋转方法,用于后续生成不同角度的模板。

import cv2
import numpy as np# 方法一:使用numpy的rot90函数旋转(按90度倍数旋转)
img = cv2.imread('../kele.png')  # 读取图像(以彩色模式)
# np.rot90参数说明:
# - 第一个参数:要旋转的图像
# - k:旋转次数(每次90度),k=1表示逆时针转90度,k=-1(或3)表示顺时针转90度
rotated_image1 = np.rot90(img, k=-1)  # 顺时针旋转90度
rotated_image2 = np.rot90(img, k=1)   # 逆时针旋转90度# 显示原图和旋转后的图像
cv2.imshow('yuantu', img)  # 原图窗口
cv2.imshow('rotated_image1', rotated_image1)  # 顺时针90度窗口
cv2.imshow('rotated_image2', rotated_image2)  # 逆时针90度窗口
cv2.waitKey(0)  # 等待按键
cv2.destroyAllWindows()  # 关闭所有窗口,释放资源# 方法二:使用OpenCV的rotate函数旋转(更直观,支持固定角度)
rotated_image = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)  # 顺时针90度
rotated_image1 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)  # 逆时针90度
rotated_image2 = cv2.rotate(img, cv2.ROTATE_180)  # 旋转180度# 显示旋转结果
cv2.imshow('shun90', rotated_image)    # 顺时针90度窗口
cv2.imshow('ni90', rotated_image1)     # 逆时针90度窗口
cv2.imshow('180', rotated_image2)      # 180度窗口
cv2.waitKey(0)  # 等待按键

两种方法对比

  • np.rot90:通过旋转次数控制(k=1/2/3/-1),适合 90 度倍数的旋转,但不够直观。
  • cv2.rotate:直接通过枚举值指定旋转方向(如ROTATE_90_CLOCKWISE),可读性更强,推荐使用。

三、支持旋转角度的模板匹配

结合多目标匹配与旋转的知识,我们就可以结合一下实现对旋转角度的模板匹配

import cv2
import numpy as np# 读取原始图像和模板
img_rgb = cv2.imread('beijing.jpg')  # 原始彩色图像
template = cv2.imread('jiantou.jpg', 0)  # 模板图像(以灰度模式读取)
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)  # 原始图像转灰度# 方法二(cv2.rotate)生成不同角度的模板(方法一被注释,原理相同)
template_rot90_clockwise_cv = cv2.rotate(template, cv2.ROTATE_90_CLOCKWISE)  # 顺时针90度
template_rot90_counterclockwise_cv = cv2.rotate(template, cv2.ROTATE_90_COUNTERCLOCKWISE)  # 逆时针90度
template_rot180_cv = cv2.rotate(template, cv2.ROTATE_180)  # 180度# 定义模板列表:包含原始模板和所有旋转后的模板(需要检测的角度)
templates = [template,  # 原始模板(0度)template_rot90_clockwise_cv,  # 顺时针90度template_rot90_counterclockwise_cv,  # 逆时针90度template_rot180_cv  # 180度
]# 设定匹配阈值:从0.9降低到0.8
# 原因:旋转后的模板与目标的匹配度可能略低(边缘、细节可能有偏差),降低阈值避免漏检
threshold = 0.8# 遍历每个模板,分别进行匹配
for temp in templates:h, w = temp.shape[:2]  # 获取当前模板的高和宽(不同旋转角度的模板尺寸可能变化)# 对当前模板执行匹配res = cv2.matchTemplate(img_gray, temp, cv2.TM_CCOEFF_NORMED)# 获取符合阈值的匹配点坐标loc = np.where(res >= threshold)# 遍历匹配点,绘制矩形框for pt in zip(*loc[::-1]):cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 1)# 显示最终匹配结果
cv2.imshow('Result', img_rgb)
cv2.waitKey(0)
cv2.destroyAllWindows()  # 关闭窗口,释放资源

核心逻辑
通过生成模板的多个旋转版本(0°、90° 顺时针、90° 逆时针、180°),分别与原始图像匹配,从而覆盖目标可能的旋转角度。这样即使目标在图像中旋转了,也能被检测到。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/921792.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921792.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

封装日期选择器组件,带有上周,下周按钮

ui图组件代码如下&#xff1a; <template><div><el-date-pickerv-model"dateRange"type"daterange"align"right"size"mini":editable"false"unlink-panelsrange-separator"至"start-placeholder&q…

基于SpringBoot+MYSQL开发的AI智能大数据医疗诊断平台

角色&#xff1a; 管理员、医生、居民 技术&#xff1a; SpringBoot、MyBatis、MySQL、Shiro、Beetl、Swagger、jQuery、Bootstrap 核心功能&#xff1a; 这是一个基于SpringBoot的社区医疗管理平台&#xff0c;旨在为管理员提供用户、角色、部门、菜单、日志等系统管理功能&am…

【MFC 小白日记】对话框编辑器里“原型图像”到底要不要勾?3 分钟看懂!

摘要&#xff1a;本文解析了MFC中Picture Control的"原型图像(Prototype Image)"属性的真实作用。该属性仅在设计时提供可视化的占位图预览&#xff0c;方便UI布局&#xff0c;运行时不会影响程序表现。文章通过对比实验验证&#xff0c;勾选后会在对话框编辑器中显示…

微信开放平台第三方平台,可以管理多个微信小程序

大家好&#xff0c;我是小悟。 这个系统可以帮助服务商更好地管理多个商家小程序&#xff0c;无需管理多个商家小程序的账号密码或者appId和secret&#xff0c;大大提升效率。 不需要频繁登录小程序后台就能完成上传代码、认证、备案、提交代码审核、发布小程序等操作。 这里录…

Java全栈学习笔记32

-- drop table t_stu;-- unique 唯一约束的列允许为null-- 如果在之后的操作中。需要某列必须为key&#xff0c;才能做一些操作的情况下。也可以使用唯一约束代替主键约束-- create table t_stu(-- studId int,-- tel varchar(11) unique,-- sex varchar(1),-- addr va…

linux升级系统,重启出现Minimal BASH-like line editingis supported

文章目录一.问题背景二.解决步骤2.1确认系统分区2.2手动引导2.3 重建grub引导2.4 还原软件包 一.问题背景 闲来无事&#xff0c;把ubuntu25.04通过sudo do-release-upgrade命令升级到了ubuntu25.10.在升级的过程会出现以下问题 1.自动替换flatpak程序为snap2.请求是否清除旧依赖…

type(类型别名)和 interface的区别和最佳实践

核心结论在大多数情况下&#xff0c;它们可以互换使用&#xff0c;都能描述对象的结构。它们的区别更多在于设计和扩展能力上。主要区别总结表特性interface (接口)type (类型别名)扩展方式使用 extends 继承interface A extends B {}使用 & 交叉类型type A B & C合并…

vscode中使用git、githup的基操

一、git提交 配置账户密码 查看用户信息 git config --global user.name # 查看用户名 git config --global user.email # 查看邮箱账户配置 # 设置全局用户名和邮箱 git config --global user.name "你的用户名" git config --global user.email "你的邮箱&q…

jsBridge接入流程

import deviceInfo from ./deviceInfo import { setRefreshToken } from ./token// 设备判断 const u navigator.userAgent export const isAndroid u.indexOf(Android) > -1 || u.indexOf(Adr) > -1 export const isIOS !!u.match(/\(i[^;];( U;)? CPU.Mac OS X/)…

【C++】19. 封装红⿊树实现set和map

文章目录一、源码及框架分析二、模拟实现map和set1、insert的实现2、iterator的实现3、map⽀持[ ]4、模拟实现的完整源代码1&#xff09;RBTree.h2&#xff09;Myset.h3&#xff09;Mymap.h4&#xff09;Test.cpp一、源码及框架分析 SGI-STL30版本源代码&#xff0c;map和set的…

面试不会问题

1. 什么是表锁&#xff1f;什么是行锁&#xff1f;什么情况下会使用表锁&#xff1f;InnoDB引擎通过“索引”实现行锁&#xff08;锁定满足条件的行&#xff09;&#xff0c;但如果操作无法通过索引定位行&#xff0c;会导致行锁失效&#xff0c;进而升级为表锁。常见的表现为&…

达梦数据库-用户,权限,角色

达梦数据库-用户,权限,角色 在达梦数据库(DM8)中,用户(User)、权限(Privilege)和角色(Role) 是数据库安全体系的核心组成部分,用于控制谁可以访问数据库、能访问哪些对象以及能执行哪些操作。 下面为你提供一份全面、详细、结构化的说明,帮助你深入理解达梦数据…

uniapp原生插件 TCP Socket 使用文档

uniapp原生插件 TCP Socket 使用文档 试了插件市场几个TCP Socket插件都不能实现监听服务器主动断开&#xff0c;于是闲来无事就开发了一款&#xff0c;本插件是一个基于 Netty 实现的 TCP 通信模块&#xff0c;用于在 UniApp 插件中提供 TCP 连接、数据发送和连接管理功能。以…

VM中CentOS 7密码重置

重启虚拟机点击e进入内核处理向下划找到UTF-8在后面输入rd.breakctrl X进入单用户模式mount -o remount,rw/sysroot进行挂盘 chroot /sysroot访问系统&#xff0c;并使用passwd修改root密码 出现乱码 输入LANGen touch /.autorelabel 保存配置 exit exit退出等待系统重新打开&…

车规级MOS管AEC-Q101认证的关键参数解读与失效模式-深圳阿赛姆

摘要本文拆解AEC-Q101认证的7大关键测试项&#xff08;UIS/温度循环/THB等&#xff09;&#xff0c;结合M120N06JC等型号实测数据&#xff0c;解析雪崩失效/栅氧击穿/绑定线脱落等故障机理&#xff0c;附选型核查表一、AEC-Q101认证核心测试项与参数解读1.1 非钳位电感开关测试…

嵌入式铁头山羊stm32-ADC实现软件触发的常规序列的单通道转换-Day25

目录 一、实验目的 二、电路连接 三、实验执行&#xff08;五步&#xff09; 1.初始化ADC的IO引脚 2.配置ADC的时钟&#xff0c;注意要小于14MHz 3.根据ADC的编程接口 实现初始化ADC的基本参数 4.配置常规序列并闭合触发输入开关 5.闭合总开关、启动并读取转换结果 四…

多模态模型出现“幻觉”,描述了表格中不存在的内容,如何修正?

在日常工作中&#xff0c;多模态模型的 “幻觉” 问题已成为影响效率的关键痛点 —— 当我们需要模型基于文档生成建议性内容&#xff08;如行业报告分析、论文数据解读等&#xff09;时&#xff0c;模型常因无法准确理解文档信息&#xff0c;输出包含 “虚构内容” 的结果&…

Java AI 智能问数:Function调用版如何重塑企业数据决策

Java AI 智能问数&#xff1a;Function调用版如何重塑企业数据决策 在数字化转型浪潮中&#xff0c;企业一把手常面临数据查询的痛点&#xff1a;分析师需编写复杂SQL&#xff0c;业务人员依赖IT支持&#xff0c;决策链条冗长。传统方法效率低下&#xff0c;而自然语言处理&…

AI-调查研究-74-具身智能 机器人学习新突破:元学习与仿真到现实迁移的挑战与机遇

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; AI炼丹日志-31- 千呼万唤始出来 GPT-5 发布&#xff01;“快的…

劳务员的就业前景如何?

劳务员的就业前景整体较为乐观&#xff0c;受到行业需求、政策支持等因素的积极影响&#xff0c;同时也面临着一些挑战。以下是具体分析&#xff1a;1.就业优势行业需求稳定&#xff1a;建筑行业作为国民经济的支柱产业&#xff0c;持续发展使得对劳务员的需求较为稳定。无论是…