opencv基础57-模板匹配cv2.matchTemplate()->(目标检测、图像识别、特征提取)

OpenCV 提供了模板匹配(Template Matching)的功能,它允许你在图像中寻找特定模板(小图像)在目标图像中的匹配位置。模板匹配在计算机视觉中用于目标检测、图像识别、特征提取等领域。

以下是 OpenCV 中使用模板匹配的基本步骤:

  1. 加载图像: 首先,加载目标图像和要匹配的模板图像。

  2. 选择匹配方法: 选择适当的匹配方法,例如 cv2.TM_CCOEFF、cv2.TM_CCOEFF_NORMED、cv2.TM_CCORR、cv2.TM_CCORR_NORMED、cv2.TM_SQDIFF 或 cv2.TM_SQDIFF_NORMED。每种方法对应不同的匹配计算方式。

  3. 应用模板匹配: 使用 cv2.matchTemplate() 函数来进行模板匹配,该函数返回匹配结果的矩阵。

  4. 找到最佳匹配位置: 在匹配结果矩阵中,通过分析像素值找到最佳匹配位置,即目标图像中的匹配位置。

模板匹配是指在当前图像 A 内寻找与图像 B 最相似的部分,一般将图像 A 称为输入图像,将图像 B 称为模板图像。模板匹配的操作方法是将模板图像 B 在图像 A 上滑动,遍历所有像素以完成匹配。

例如,在图 15-1 中,希望在图中的大图像“lena”内寻找左上角的“眼睛”图像。此时,大图像“lena”是输入图像,“眼睛”图像是模板图像。查找的方式是,将模板图像在输入图像内从左上角开始滑动,逐个像素遍历整幅输入图像,以查找与其最匹配的部分。

在这里插入图片描述

模板匹配函数说明

在 OpenCV 内,模板匹配是使用函数 cv2.matchTemplate()实现的。该函数的语法格式为:

result = cv2.matchTemplate(image, templ, method[, mask ] )

其中:

  • image 为原始图像,必须是 8 位或者 32 位的浮点型图像。
  • templ 为模板图像。它的尺寸必须小于或等于原始图像,并且与原始图像具有同样的类
    型。
  • method 为匹配方法。该参数通过 TemplateMatchModes 实现,有 6 种可能的值,如表 15-1 所示。

在这里插入图片描述

  • mask 为模板图像掩模。它必须和模板图像 templ 具有相同的类型和大小。通常情况下该值使用默认值即可。当前,该参数仅支持 TM_SQDIFF 和 TM_CCORR_NORMED 两个值。

函数 cv2.matchTemplate()的返回值 result 是由每个位置的比较结果组合所构成的一个结果集,类型是单通道 32 位浮点型。如果输入图像(原始图像)尺寸是 WH,模板的尺寸是 wh,
则返回值的大小为(W-w+1)*(H-h+1)。
在进行模板匹配时,模板在原始图像内遍历。在水平方向上:
I 表示输入图像,T 表示模板,R 表示输出的结果图像,x 和 y 表示位置信息。

  • 遍历的起始坐标是原始图像左数第 1 个像素值(序号从 1 开始)。
  • 最后一次比较是当模板图像位于原始图像的最右侧时,此时其左上角像素点所在的位置是 W-w+1。
    因此,返回值 result 在水平方向上的大小是 W-w+1(水平方向上的比较次数)。

在垂直方向上:

  • 遍历的起始坐标从原始图像顶端的第 1 个像素开始。
  • 最后一次比较是当模板图像位于原始图像的最下端时,此时其左上角像素点所在位置是H-h+1。

所以,返回值 result 在垂直方向上的大小是 H-h+1(垂直方向上的比较次数)。
如果原始图像尺寸是 WH,模板的尺寸是 wh,则返回值的大小为(W-w+1)(H-h+1)。也就是说,模板图像要在输入图像内比较(W-w+1)(H-h+1)次。

太抽象了再看看下面的说明看看能不能好理解一点

例如,在图 15-2 中,左上方的 2×2 小方块是模板图像,右下方的 10×10 图像是输入图像
(原始图像)。在进行模板匹配时:

  1. 首先将模板图像置于输入图像的左上角。
  2. 模板图像在向右移动时,最远只能位于输入图像的最右侧边界处,此时模板图像左上角的像素对应着输入图像的第 9 列(输入图像宽度-模板图像宽度+1 = 10-2+1 = 9)。
  3. 模板图像在向下移动时,最远只能位于输入图像最下端的边界处。此时模板图像左上角的像素对应着输入图像的第 9 行(输入图像高度-模板图像高度+1 = 10-2+1 = 9)。
    根据上述分析可知,比较结果 result 的大小满足(W-w+1)*(H-h+1),在上例中就是(10-2+1)×(10-2+1),即 9×9。也就是说,模板图像要在输入图像内总计比较 9×9 = 81 次,这些比较结果将构成一个 9×9 大小的二维数组。

在这里插入图片描述
这样感觉有点懂了。

这里需要注意的是,函数 cv2.matchTemplate()通过参数 method 来决定使用不同的查找方法。对于不同的查找方法,返回值 result 具有不同的含义。

例如:

  • method 的值为 cv2.TM_SQDIFF 和 cv2.TM_SQDIFF_NORMED 时,result 值为 0 表示匹
    配度最好,值越大,表示匹配度越差。
  • method 的值为 cv2.TM_CCORR、cv2.TM_CCORR_NORMED、cv2.TM_CCOEFF 和
    cv2.TM_CCOEFF_NORMED 时,result 的值越小表示匹配度越差,值越大表示匹配度越好。

从上述分析可以看出,查找方法不同,结果的判定方式也不同。在查找最佳匹配时,首先要确定使用的是何种 method,然后再确定到底是查找最大值,还是查找最小值。

代码示例:使用函数 cv2.matchTemplate()进行模板匹配。

要求参数 method 的值设置为 cv2.TM_SQDIFF,显示函数的返回结果及匹配结果。

先到网上找个图,然后从图中再截取一部分另存为一个图。

在这里插入图片描述

在这里插入图片描述

代码如下:

import cv2from matplotlib import pyplot as pltimg1 = cv2.imread('toukui.png')
#将图片转换为灰度图
img = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)template1 = cv2.imread('toukui2.png')template = cv2.cvtColor(template1,cv2.COLOR_BGR2GRAY)th, tw = template.shape[::]
rv = cv2.matchTemplate(img,template,cv2.TM_SQDIFF)minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(rv)
topLeft = minLoc
bottomRight = (topLeft[0] + tw, topLeft[1] + th)
cv2.rectangle(img,topLeft, bottomRight, 255, 2)
plt.subplot(121),plt.imshow(rv,cmap = 'gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img,cmap = 'gray')
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
plt.show()

运行效果:

在这里插入图片描述
简单的目标检测效果就来了。

多模板匹配

也就是说目标检测时 出现了多个目标,在前面的例子中,我们在输入图像 中搜索其戴头盔,该子图在整个输入图像内仅出现了一次。但是,有些情况下,如果摄像头下面现在站了3个戴头盔的人,这时就需要找出多个匹配结果。而函数 cv2.minMaxLoc()仅仅能够找出最值,无法给出所有匹配区域的位置信息。所以,要想匹配多个结果,使用函数 cv2.minMaxLoc()是无法实现的,需要利用阈值进行处理。

下面分步骤介绍如何获取多模板匹配的结果。

1. 获取匹配位置的集合

函数 where()能够获取模板匹配位置的集合。对于不同的输入,其返回的值是不同的。

  • 当输入(参数)是一维数组时,返回值是一维索引,只有一组索引数组。
  • 当输入是二维数组时,返回的是匹配值的位置索引,因此会有两组索引数组表示返回值的位置。

以下代码查找在一维数组 a 中,数值大于 5 的元素的索引(即该元素所在的位置,数组的索引从 0 开始):

import numpy as np
a=np.array([3,6,8,1,2,88])
b=np.where(a>5)
print(b)

该段代码返回的结果为:

(array([1, 2, 5], dtype=int64),)

说明索引值为 1、2、5 的数组元素,它们的值是大于 5 的


上面介绍的是输入值为一维数组时的情况。

当输入值是二维数组时,函数 where()会返回满足条件的值在二维数组中的索引。

例如,以下代码查找在二维数组 am 中,值大于 5 的元素的索引:

import numpy as np
am=np.array([[3,6,8,77,66],[1,2,88,3,98],[11,2,67,5,2]])
b=np.where(am>5)
print(b)

该段代码返回的结果为:

(array([0, 0, 0, 0, 1, 1, 2, 2], dtype=int64),
array([1, 2, 3, 4, 2, 4, 0, 2], dtype=int64))

上述结果说明,存在二维数组 am,它的值为:

[[ 3 6 8 77 66]
[ 1 2 88 3 98]
[11 2 67 5 2]]

其中,位置[0, 1]、[0, 2]、[0, 3]、[0, 4]、[1, 2]、[1, 4]、[2, 0]、[2, 2]上的元素值大于 5。

综上所述,函数 np.where()可以找出在函数 cv2.matchTemplate()的返回值中,哪些位置上的值是大于阈值 threshold 的。

在具体实现时,可以采用的语句为:

loc = np.where( res >= threshold)

式中:

  • res 是函数 cv2.matchTemplate()进行模板匹配后的返回值。
  • threshold 是预设的阈值
  • loc 是满足“res >= threshold”的像素点的索引集合。例如,在上面的二维数组 am 中,返回的大于 5 的元素索引集合为(array([0, 0, 0, 0, 1, 1, 2, 2], dtype=int64), array([1, 2, 3, 4,2, 4, 0, 2], dtype=int64))。返回值 loc 中的两个元素,分别表示匹配值的行索引和列索引。

2. 循环坐标值

这个没啥看头,知道什么叫循环就行

比如要处理多个值,通常需要用到循环。
例如,有一个列表,其中的值为 71、23、16,希望将这些值逐个输出,可以这样写代码:

value = [71,23,16]
for i in value:
print('value 内的值:', i)

运行上述代码,得到的输出结果为:

value 内的值: 71
value 内的值: 23
value 内的值: 16

因此,在获取匹配值的索引集合后,可以采用如下语句遍历所有匹配的位置,对这些位置做标记:
for i in 匹配位置集合:标记匹配位置。

3. 在循环中使用函数zip()

函数 zip()用可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

例如,以下代码使用函数 zip()将 t 内对应的元素打包成一个个元组,并打印了由这些元组组成的列表:

x = [1,2,3]
y = [4,5,6]
z = [7,8,9]
t = (x,y,z)
print(t)
for i in zip(*t):print(i)

上述代码中,语句 print(t)将 t 内的元素输出,结果为:

([1, 2, 3], [4, 5, 6], [7, 8, 9])

循环语句 for i in zip(*t)将 t 内的元素打包成元组后输出,结果为:

(1, 4, 7)
(2, 5, 8)
(3, 6, 9)

因此,如果希望循环遍历由 np.where()返回的模板匹配索引集合,可以采用的语句为:

for i in zip(*模板匹配索引集合):标记处理

例如,对于前面提到的数组 am,使用函数 zip()循环,就可以得到其中大于 5 的元素索引
的集合:

import numpy as np
am=np.array([[3,6,8,77,66],[1,2,88,3,98],[11,2,67,5,2]])
print(am)
b=np.where(am>5)
for i in zip(*b):print(i)

上述代码的输出结果为:

[[ 3 6 8 77 66]
[ 1 2 88 3 98]
[11 2 67 5 2]]
(0, 1)
(0, 2)
(0, 3)
(0, 4)
(1, 2)
(1, 4)
(2, 0)
(2, 2)

4. 调整坐标

函数 numpy.where()可以获取满足条件的模板匹配位置集合,然后可以使用函数cv2.rectangle()在上述匹配位置绘制矩形来标注匹配位置
使用函数 numpy.where()在函数 cv2.matchTemplate()的输出值中查找指定值,得到的形式为“(行号,列号)”的位置索引。

但是,函数 cv2.rectangle()中用于指定顶点的参数所使用的是形
式为“(列号,行号)”的位置索引。所以,在使用函数 cv2.rectangle()绘制矩形前,要先将函数numpy.where()得到的位置索引做“行列互换”。可以使用如下语句实现 loc 内行列位置的互换:loc[::-1]
如下语句将 loc 内的两个元素交换位置:

import numpy as np
loc = ([1,2,3,4],[11,12,13,14])
print(loc)
print(loc[::-1])

其中,语句 print(loc)所对应的输出为:

([1, 2, 3, 4], [11, 12, 13, 14])

语句 print(loc[::-1])所对应的输出为:

([11, 12, 13, 14], [1, 2, 3, 4])

5. 标记匹配图像的位置

最后一步就用 函数 cv2.rectangle()可以标记匹配图像的具体位置,分别指定要标记的原始图像、对角顶点、颜色、矩形边线宽度即可。
关于矩形的对角顶点:

  • 其中的一个对角顶点 A 可以通过 for 循环语句从确定的满足条件的“匹配位置集合”内获取。
  • 另外一个对角顶点,可以通过顶点 A 的位置与模板的宽(w)和高(h)进行运算得到。

因此,标记各个匹配位置的语句为:

for i in 匹配位置集合:cv2.rectangle(输入图像,i, (i[0] + w, i[1] + h), 255, 2)

代码示例:使用模板匹配方式,标记在输入图像内与模板图像匹配的多个子图像。

代码如下:

import cv2
import numpy as np
img = cv2.imread('lena4.bmp',0)
template = cv2.imread('lena4Temp.bmp',0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.9
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), 255, 1)cv2.imshow("template",template)
cv2.imshow("result1",img)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果如下:

在这里插入图片描述
可以看到输入图像内多个与模板图像匹配的子图被标记出来

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

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

相关文章

ClickHouse(十三):Clickhouse MergeTree系列表引擎 - ReplicingMergeTree

进入正文前,感谢宝子们订阅专题、点赞、评论、收藏!关注IT贫道,获取高质量博客内容! 🏡个人主页:含各种IT体系技术,IT贫道_Apache Doris,大数据OLAP体系技术栈,Kerberos安全认证-CSDN博客 &…

【Rust招聘】【理想汽车】rust高级开发工程师(35K-50K)

职位描述: 1、参与设计开发下一代车联网边缘计算引擎的开发。 2、深入发掘和分析业务需求,提出技术及产品改进建议,撰写技术方案和系统设计。 3、把握系统设计复杂度,制定计划,及时沟通、高效执行。 4、勤于梳理工作中…

vb6的dictionary类

vb6的dictionary类 vb6 原生容器, 除了array还有collection, 没有原生的dictionary和set类, 在microsoft script runtime库(scrrun.dll) 中有一个dictionary类, 功能还算强大, 可以较好处理key-value这样的字典, 我甚至觉得用它也完全可以代替原生的collection类. microsoft sc…

深入探索二叉树算法:理解、构建和应用C语言

引言 二叉树是计算机科学中的一种重要数据结构,它在各种算法和应用中都扮演着重要角色。本篇博客将带您深入探索二叉树的世界,从基本概念到高级应用,逐步展开二叉树的奥秘,助您更好地理解、构建和应用二叉树算法。 什么是二叉树…

Nginx反向代理配置+负载均衡集群部署

文章目录 负载均衡反向代理基础环境部署:什么是代理实验环境图流量过程 环境部署准备两台Web服务器安装Nginx准备页面内容添加主机名 代理服务器配置 修改windos hosts文件测试:终端浏览器 负载均衡反向代理基础环境部署: 什么是代理 正向代…

2023-08-09力扣每日一题

链接&#xff1a; 1281. 整数的各位积和之差 题意&#xff1a; 十进制每一位的积减去每一位的和 解&#xff1a; 十进制位处理 实际代码&#xff1a; #include<iostream> using namespace std; int subtractProductAndSum(int n) {int t11,t20;while(n){t1*n%10;t…

爬虫学习记录(持续更新)

一、问题记录 1.使用webdriver报错AttributeError: str object has no attribute capabilities 解决&#xff1a;目前使用的selenium版本是4.11.2&#xff0c;可以不必设置driver.exe的路径&#xff0c;selenium可以自己处理浏览器和驱动程序&#xff0c;因此&#xff0c;使用…

【公众号】如何为公众号引流的文章,吸引关注

引流到公众号吸引关注 在当今的数字时代&#xff0c;社交媒体和内容营销已经成为企业推广和吸引关注的重要手段。微信公众号作为中国最大的社交媒体平台之一&#xff0c;拥有庞大的用户基础和丰富的功能特性&#xff0c;为企业提供了一个理想的渠道来与潜在客户建立联系并吸引…

Django操作cookie、Django操作session、Django中的Session配置、CBV添加装饰器、中间件、csrf跨站请求

一、Django操作cookie cookie的原理cookie的工作原理是&#xff1a;由服务器产生内容&#xff0c;浏览器收到请求后保存在本地&#xff1b;当浏览器再次访问时&#xff0c;浏览器会自动带上Cookie&#xff0c;这样服务器就能通过Cookie的内容来判断这个是“谁”了。1.设置cook…

八月组队学习来了!

Datawhale学习 联合主办&#xff1a;Datawhale&#xff0c;人民邮电出版社 本期学习由Datawhale和人民邮电出版社异步社区联合发起&#xff0c;学习大纲如下&#xff08;文末整理了这次学习的所有资料&#xff09;&#xff1a; 参与学习 ▶ 活动时间&#xff1a;学习活动 8月1…

二叉树(4)------收尾

1)最大二叉树 654. 最大二叉树 - 力扣&#xff08;LeetCode&#xff09; 题目解析: 1)首先我们找到了整个数组中最大的元素作为我们的根节点&#xff0c;然后再从左区间中找到最大的元素作为当前根节点的左子树&#xff0c;然后再从右区间里面找到最大的元素作为根节点的右子树…

CSS媒体查询(@media)全面解析

随着移动设备的快速普及&#xff0c;用户不再只是通过传统的电脑系来浏览 Web 内容&#xff0c;越来越多的用户开始使用各种尺寸的智能手机、平板电脑或者其它设备来浏览 Web 内容&#xff0c;为了确保使用不同设备的用户都能拥有不错的体验就需要用到媒体查询。 媒体查询是 C…

直接在html中引入Vue.js的cdn来实现一个简单的博客

摘要 其实建立一个博客系统是非常简单的&#xff0c;有很多开源的程序&#xff0c;如果你不喜欢博客系统&#xff0c;也可以自己开发&#xff0c;也可以自己简单做一个。我这次就是用Vue.js和php做后端服务实现一个简单的博客。 界面 代码结构 代码 index.html <!DOCTYP…

maven的入门使用

maven的入门使用 1.Maven&#xff08;Maven Apache&#xff09;是一个流行的项目构建和管理工具&#xff0c;2.项目结构和POM文件&#xff1a;3.POM文件&#xff08;Project Object Model&#xff09;4.依赖管理&#xff1a; 在POM文件中5.生命周期和构建过程1.前言2.插件系统3…

Centos-6.3安装使用MongoDB

安装说明 系统环境&#xff1a;Centos-6.3 安装软件&#xff1a;mongodb-linux-x86_64-2.2.2.tgz 下载地址&#xff1a;http://www.mongodb.org/downloads 安装机器&#xff1a;192.168.15.237 上传位置&#xff1a;/usr/local/ 软件安装位置&#xff1a;/usr/local/mongodb 数…

uni-app使用vue语法进行开发注意事项

目录 uni-app 项目目录结构 生命周期 路由 路由跳转 页面栈 条件编译 文本渲染 样式渲染 条件渲染 遍历渲染 事件处理 事件修饰符 uni-app 项目目录结构 组件/标签 使用&#xff08;类似&#xff09;小程序 语法/结构 使用vue 具体项目目录如下&#xff1a; 生命…

【深度学习注意力机制系列】—— SENet注意力机制(附pytorch实现)

深度学习中的注意力机制&#xff08;Attention Mechanism&#xff09;是一种模仿人类视觉和认知系统的方法&#xff0c;它允许神经网络在处理输入数据时集中注意力于相关的部分。通过引入注意力机制&#xff0c;神经网络能够自动地学习并选择性地关注输入中的重要信息&#xff…

Scikit-learn聚类方法代码批注及相关练习

一、代码批注 代码来自&#xff1a;https://scikit-learn.org/stable/auto_examples/cluster/plot_dbscan.html#sphx-glr-auto-examples-cluster-plot-dbscan-py import numpy as np from sklearn.cluster import DBSCAN from sklearn import metrics from sklearn.datasets …

DNS部署与安全详解(下)

文章目录 前言一、指定区域解析配置二、DNS服务器对外名称显示配置三、转发器使用配置四、配置辅助&#xff08;备份&#xff09;服务器五、如何让虚拟机可以真实上网六、为DNS服务器配置别名 前言 上一篇博客我们已经在Windows server2003的虚拟机上下载了DNS软件&#xff0c;…

使用Spark ALS模型 + Faiss向量检索实现用户扩量实例

1、通过ALS模型实现用户/商品Embedding的效果&#xff0c;获得其向量表示 准备训练数据&#xff0c; M (U , I, R) 即 用户集U、商品集I、及评分数据R。 &#xff08;1&#xff09;商品集I的选择&#xff1a;可以根据业务目标确定商品候选集&#xff0c;比如TopK热度召回、或…