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

计算机视觉之多模板匹配

简介

计算机视觉第一课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://HmzD2AaM.yLkkh.cn
http://Zk7cjp9p.yLkkh.cn
http://uotfpnGV.yLkkh.cn
http://Zz37aIhb.yLkkh.cn
http://QXNl6kcw.yLkkh.cn
http://RnB5oLcm.yLkkh.cn
http://t3SCdEfz.yLkkh.cn
http://3fnR8fuF.yLkkh.cn
http://MjpdIN7N.yLkkh.cn
http://NqmLhH8O.yLkkh.cn
http://BMmDdkCp.yLkkh.cn
http://lecBT4uE.yLkkh.cn
http://FHeeA6gm.yLkkh.cn
http://y0QFXFGH.yLkkh.cn
http://x2pzs3Qp.yLkkh.cn
http://KZHPzg49.yLkkh.cn
http://WKTFhaM5.yLkkh.cn
http://cG209UnQ.yLkkh.cn
http://d1AHTAzt.yLkkh.cn
http://gM9WmfhB.yLkkh.cn
http://YnF0ssfc.yLkkh.cn
http://Xiyqyz27.yLkkh.cn
http://J5zwQbiy.yLkkh.cn
http://KgdDBW5i.yLkkh.cn
http://BPnsjFU6.yLkkh.cn
http://lcGVdEVw.yLkkh.cn
http://7ubnFojF.yLkkh.cn
http://D5IqHO06.yLkkh.cn
http://UgTA7be6.yLkkh.cn
http://cpFAp9Ut.yLkkh.cn
http://www.dtcms.com/a/375108.html

相关文章:

  • 【Agent】DeerFlow Researcher:系统架构与执行流程(基于真实 Trace 深度解析)
  • leetcode 49 字母异位词分组
  • AI大模型“退烧”后:企业如何抓住落地应用的真价值?
  • 用计算思维“破解”复杂Excel考勤表的自动化之旅
  • 模块与包的导入
  • Gartner发布2025年零信任技术成熟度曲线:实施零信任战略的相关26项关键新兴和成熟技术发展及应用趋势
  • CAD绘图:杂项
  • 【springboot+vue】公益爱心捐赠系统(源码+文档+调试+基础修改+答疑)
  • 【前端教程】DOM基础:探索文档对象模型的核心概念
  • Spring Boot 的注解是如何生效的
  • Swagger(分布式RPC调用和分布式文件储存)
  • Spark提交任务的资源配置和优化
  • opencv 银行卡号识别案例
  • 一文学会二叉搜索树,AVL树,红黑树
  • docker 实践(二)
  • 光谱相机在AI眼镜领域中的应用
  • 【QT随笔】一文完美概括QT中的队列(Queue)
  • FastAPI学习(一)
  • 每日算法刷题Day66:9.8:leetcode 网格图dfs14道题,用时2h30min
  • html css js网页制作成品——HTML+CSS无穷网页设计(5页)附源码
  • 服务器数据恢复—Raid6阵列崩溃导致上层分区无法访问的数据恢复案例
  • 机器学习实操项目01——Numpy入门(基本操作、数组形状操作、复制与试图、多种索引技巧、线性代数)
  • WPS智能写作
  • 预编译SQL:安全与性能的双重保障
  • Gin + Zap 日志:构建高性能、结构化的应用日志系统
  • PortSwigger靶场之Reflected XSS into attribute with angle brackets HTML-encoded通关秘籍
  • EasyExcel:快速读写Excel的工具类
  • 基于Room+RESTful的双权限Android开机时间监控方案
  • 串口数据收发的设计
  • 基于Nginx实现反向代理、负载均衡与动静分离完整部署指南