【OpenCV】 模版匹配 | 霍夫变换 | 霍夫线、圆检测

news2024/11/13 3:48:52

Ⅰ. 模版匹配和霍夫变换

0x00 模板匹配

原理
所谓的模板匹配,就是在给定的图片中查找和模板最相似的区域,该算法的输入包括模板和图片,整个任务的思路就是按照滑窗的思路不断的移动模板图片,计算其与图像中对应区域的匹配度,最终将匹配度最高的区域选择为最终的结果。


模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv里有6种,然后将每次计算的结果放入一个矩阵里,作为结果输出。

设原图形是 A\times B 大小,而模板是 a\times b 大小,则输出结果的矩阵为  (A-a+1)\times (B-b+1)

实现流程:

准备两幅图像:

1.原图像(I):在这幅图中,找到与模板相匹配的区域

2.模板(T):与原图像进行比对的图像块

滑动模板图像和原图像进行比对:



将模板块每次移动一个像素 (从左往右,从上往下),在每一个位置,都计算与模板图像的相似程度。

对于每一个位置将计算的相似结果保存在结果矩阵  (R)  中。如果输入图像的大小 (W\times H) 

且模板图像的大小(wxh),则输出矩阵R的大小为 (W-w + 1,\, H-h + 1) 

将R显示为图像,如下图所示:

 
获得上述图像后,查找最大值所在的位置,那么该位置对应的区域就被认为是最匹配的。对应的区域就是以该点为顶点,长宽和模板图像一样大小的矩阵。

实现
我们使用OpenCV中的方法实现模板匹配。

💬API

res = cv.matchTemplate(img,template,method)

参数:

  • img: 要进行模板匹配的图像
  • Template :模板
  • method:实现模板匹配的算法,主要有:
  1.  平方差匹配(CV_TM_SQDIFF):利用模板与图像之间的平方差进行匹配,最好的匹配是0,匹配越差,匹配的值越大。
  2.  相关匹配(CV_TM_CCORR):利用模板与图像间的乘法进行匹配,数值越大表示匹配程度较高,越小表示匹配效果差。
  3.  利用相关系数匹配(CV_TM_CCOEFF):利用模板与图像间的相关系数匹配,1表示完美的匹配,-1表示最差的匹配。

完成匹配后,使用cv.minMaxLoc()方法查找最大值所在的位置即可。如果使用平方差作为比较方法,则最小值位置是最佳匹配位置。

  • TM_SQDIFF:计算平方不同,计算出来的值越小,越相关
  • TM_CCORR:计算相关性,计算出来的值越大,越相关
  • TM_CCOEFF:计算相关系数,计算出来的值越大,越相关
  • TM_SQDIFF_ NORMED:计算归一化平方不同,计算出来的值越接近0,越相关
  • TM_CCORR_ NORMED:计算归一化相关性,计算出来的值越接近1,越相关
  • TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关
     

💎示例:

img = cv2.imread('sun.jpg',0)
template = cv2.imread('s.jpg',0)
h, w = template.shape[:2]
methods =['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED','cv2.TM_CCORR', 'cv2.TM_CCOEFF_NORMED','cv2.TM_SQDIFF','cv2.TM_SQDIFF_NORMED']
for meth in methods:
    img2 = img.copy()

    #匹配方法的真值
    method =eval(meth)
    print(method)
    res = cv2.matchTemplate(img, template, method)
    min_val,max_val,min_loc,max_loc = cv2.minMaxLoc(res)
    #
    if method in [cv2.TM_SQDIFF,cv2.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc
    bottom_right = (top_left[0]+ w, top_left[0]+ h)
    #
    cv2.rectangle(img2,top_left,bottom_right,255,2)

    plt.figure()
    plt.subplot(121),plt.imshow(res,cmap='gray')
    plt.xticks([]),plt.yticks([])#隐藏坐标轴
    plt.subplot(122),plt.imshow(img2,cmap='gray')
    plt.xticks([]),plt.yticks([])
    plt.suptitle(meth)
    plt.show()

 拓展:模板匹配不适用于尺度变换,视角变换后的图像,这时我们就要使用关键点匹配算法,比较经典的关键点检测算法包括SIFT和SURF等。

主要的思路是首先通过关键点检测算法获取模板和测试图片中的关键点;

然后使用关键点匹配算法处理即可,这些关键点可以很好的处理尺度变化、视角变换、旋转变化、光照变化等,具有很好的不变性。

0x01 霍夫变换

霍夫变换常用来提取图像中的直线和圆等几何形状,如下图所示:

 原理

在笛卡尔坐标系中,一条直线由两个点A = (x1,\, y1)B = (x2,\, y2)

 将直线 y= kx + q 可写成关于 (k,q) 的函数表达式:

 对应的变换通过图形直观的表示下:

 变换后的空间我们叫做霍夫空间。即:笛卡尔坐标系中的一条直线,对应霍夫空间中的每一个点。

反过来同样成立,霍夫空间的一条线,对应笛卡尔坐标系中的一个点,如下所指示:

 我们再来看下A、B两个点,对应霍夫空间的情形:

 再看下三点共线的情况:

可以看出如果在笛卡尔坐标系的点共线,那么这些点在霍夫空间中对应的直线交于一点 

如果不止存在一条直线时,如下所示:

 我们选择尽可能多的直线汇成的点,上图中三条直线汇成的A、B两点,将其对应笛卡尔坐标系中的直线:

 到这里我们似乎已经完成了霍夫变换的求解。但如果遇到如下图的情况时:

 上图中的直线是x = 2,那 (k,q) 怎么确定呢?

为了解决这个问题,我们考虑将笛卡尔坐标系转换为极坐标

 在极坐标下是一样的,极坐标中的点对应霍夫空间的线,这时的霍夫空间是不在是参数 (k.q) 的空间,而是 (\rho ,\theta ) 的空间,\rho 是原点到直线的垂直距离, \theta 表示直线的垂线与横轴顺时针方向的夹角,垂直线的角度为0度,水平线的角度是180度。

 我们只要求得霍夫空间中的交点的位置,即可得到原坐标系下的直线。

实现流程

假设有一个大小为 100\times 100 的图片,使用霍夫变换检测图片中的直线,则步骤如下所示:

直线都可以使用 (\rho ,\theta )  表示,首先创建一个2D数组,我们叫做累加器,初始化所有值为0,行表示 \rho,列表示 \theta 。

该数组的大小决定了结果的准确性,若希望角度的精度为1度,那就需要180列。对于 \rho,最大值为图片对角线的距离,如果希望精度达到像素级别,行数应该与图像的对角线的距离相等。

  •  取直线上的第一个点 (x,y),将其带入直线在极坐标中的公式中,然后遍历θ的取值:0,1,2,...,180,分别求出对应的ρ值,如果这个数值在上述累加器中存在相应的位置,则在该位置上加1.
  •  取直线上的第二个点,重复上述步骤,更新累加器中的值。对图像中的直线上的每个点都直线以上步骤,每次更新累加器中的值。
  •  搜索累加器中的最大值,并找到其对应的(ρ,θ),就可将图像中的直线表示出来

0x02  霍夫线检测

💬API

cv.HoughLines(img, rho, theta, threshold)

参数:

  • img::检测的图像,要求是二值化的图像,所以在调用霍夫变换之前首先要进行二值化,或者进行Canny边缘检测
  • rho、theta:\rho 和 \theta 的精确度
  • threshold: 阈值,只有累加器中的值高于该阈值时才被认为是直线。

霍夫线检测的整个流程如下图所示,这是在stackflow上一个关于霍夫线变换的解释:

💎 示例:

检测下述图像中的直线:

# 1.加载图片,转为二值图
img = cv2.imread('img1.jpg')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150)

# 2.霍夫直线变换
lines = cv2.HoughLines(edges, 0.8, np.pi / 180, 150)
# 3.将检测的线绘制在图像上(注意是极坐标噢)
for line in lines:
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    x1 = int(x0 + 1000 * (-b))
    y1 = int(y0 + 1000 * (a))
    x2 = int(x0 - 1000 * (-b))
    y2 = int(y0 - 1000 * (a))
    cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0))
# 4. 图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.imshow(img[:,:,::-1]),plt.title('Hoff transform line detection')
plt.xticks([]), plt.yticks([])
plt.show()


结果:
 

0x03 霍夫圆检测 

原理
圆的表示式是: (x-a)^2 +(y-b)^2=r

其中a和b表示圆心坐标,r表示圆半径,因此标准的霍夫圆检测就是在这三个参数组成的三维空间累加器上进行圆形检测,此时效率就会很低,所以OpenCV中使用霍夫梯度法进行圆形的检测。

霍夫梯度法将霍夫圆检测范围两个阶段,第一阶段检测圆心,第二阶段利用圆心推导出圆半径。

  • 圆心检测的原理:圆心是圆周法线的交汇处,设置一个阈值,在某点的相交的直线的条数大于这个阈值就认为该交汇点为圆心。
  • 圆半径确定原理:圆心到圆周上的距离(半径)是相同的,确定一个阈值,只要相同距离的数量大于该阈值,就认为该距离是该圆心的半径。

原则上霍夫变换可以检测任何形状,但复杂的形状需要的参数就多,霍夫空间的维数就多,因此在程序实现上所需的内存空间以及运行效率上都不利于把标准霍夫变换应用于实际复杂图形的检测中。霍夫梯度法是霍夫变换的改进,它的目的是减小霍夫空间的维度,提高效率。


在OpenCV中检测图像中的圆环使用的是API是:

circles = cv.HoughCircles(image, method, dp, minDist, param1=100, param2=100, minRadius=0,maxRadius=0 )

参数:

  • image:输入图像,应输入灰度图像
  • method:使用霍夫变换圆检测的算法,它的参数是CV_HOUGH_GRADIENT
  • dp:霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2时霍夫空间是输入图像空间的一半,以此类推
  • minDist为圆心之间的最小距离,如果检测到的两个圆心之间距离小于该值,则认为它们是同一个圆心
  • param1:边缘检测时使用Canny算子的高阈值,低阈值是高阈值的一半。
  • param2:检测圆心和确定半径时所共有的阈值
  • minRadius和maxRadius为所检测到的圆半径的最小值和最大值

返回:

  • circles:输出圆向量,包括三个浮点型的元素——圆心横坐标,圆心纵坐标和圆半径

总结:

1. 模板匹配
原理:在给定的图片中查找和模板最相似的区域
API:利用cv.matchTemplate()进行模板匹配,然后
使用cv.minMaxLoc()搜索最匹配的位置。

2. 霍夫线检测
原理:将要检测的内容转换到霍夫空间中,利用累加器统计最优解,将检测结果表示处理
API:cv2.HoughLines()
注意:该方法输入是的二值化图像,在进行检测前要将图像进行二值化处理

3. 霍夫圆检测
方法:霍夫梯度法

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

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

相关文章

春节要闻回顾 | 美SEC被列入Genesis债权人名单;亚马逊或将推出专注于游戏的NFT项目...

春节期间区块链行业要闻回顾:产业方面,达沃斯央行数字货币小组认可CBDC是央行货币的未来,但目前部署存在困难,亚马逊或将推出专注于游戏的NFT项目;政策方面,拜登政府将在未来几个月公布数字资产优先事项&am…

数据结构——顺序表(三)

数据结构 文章目录数据结构一、什么是顺序表二、顺序表的创建1.静态顺序表2.动态数据表三、顺序表的初始化、销毁四、顺序表的插入1.尾插2.头插3.任意插入总结一、什么是顺序表 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组…

Python实例方法、静态方法和类方法详解

和类属性一样,类方法也可以进行更细致的划分,具体可分为类方法、实例方法和静态方法。和类属性的分类不同,对于初学者来说,区分这 3 种类方法是非常简单的,即采用 classmethod 修饰的方法为类方法;采用 sta…

FreeRTOS消息队列

消息队列是一种常用于任务间通信的数据结构。通过消息队列服务,任务或 中断服务例程可以将一条或多条消息放入消息队列中,同样,一个或多个任务可 以从消息队列中获得消息。本章将向大家介绍 FreeRTOS 的消息队列,通过本章 的学习&…

238. 除自身以外数组的乘积

【答案解析】:暴力不考虑其他的因素的话,将所有数据乘积起来,然后遍历数组除以当前位置数据即可。更优解法:将乘积分为两次进行,第一次先将每个位置左边的数据乘积计算出来放到返回数组中,后边第二次循环 将…

【Java面试(二)】冒泡排序的实现及优化

文章目录前言冒泡排序初步实现冒泡排序_优化_减少比较次数冒泡排序_优化_减少冒泡次数冒泡排序_优化_进一步优化比较次数总结前言 今天我们来学习与排序相关的面试题,首先我们先来学习冒泡排序,那什么是冒泡排序呢,它的关键在于数组中相邻元素…

变聪明的方法就是学习,每个人最终都会与生活和解,连村西透仿佛也捡回了昔日的勇气。

文章目录❤️‍🔥 序❤️‍🔥 往事如风迹难寻 - 成为创作者的契机❤️‍🔥 新星计划遇善者 - 出道即是巅峰MVP❤️‍🔥 知行合一心依旧 - 初心不改坚持创作❤️‍🔥 知易行难搞规划 - 这是不能说的秘密❤️‍&#x1f…

中国为何就不能有自己的豪华MPV?

文|智能相对论作者| 陈明涛是时候重新认识海外汽车品牌和国产汽车品牌的MPV了。去年,曾有雷克萨斯LM在碰撞后出现全车车门无法打开,之后车辆起火酿成悲剧,引发了全网对MPV碰撞安全的高度关注。前段时间丰田埃尔法再登热搜,这次不是…

2023最新Python国内镜像源,亲测可用

1、镜像源 pip包管理工具可以下载第三方库到本地使用,第三方库的来源地址称之为镜像源,镜像源中存放了大量的开源库供我们下载使用。pip的默认镜像源地址在国外,下载很慢,本文收集了当前国内常用的镜像源,速率由快到慢…

Java多线程 - 定时器-并发与并行-线程生命周期

文章目录多线程补充定时器并发和并行线程的生命周期多线程补充 定时器 定时器介绍: 定时器是一种控制任务延时调用,或者周期调用的技术。 作用:闹钟、定时邮件发送。 定时器实现方式: 方式一:Timer 方式二: ScheduledExecutorSe…

java程序报错后的排错思路

目前总结出来三个字:看日志! 而且是从左到右一个单词一个单词的看。   举个例子:   Spring框架下的一个Demo,启动时报出了以下错误。 一、看异常类型   首先,能看到异常是从引入的SpringFramework依赖中报出来的&#xf…

[数据结构基础]排序算法第三弹 -- 快速排序

目录 一. 快速排序的基本思想 二. 快速排序的递归实现 2.1 单趟快速排序的实现 2.1.1 Hoare法实现单趟快排 2.1.2 挖坑法实现单趟快排 2.1.3 前后指针法实现单趟快排 2.2 递归快排的整体实现 三. 快速排序的时间复杂度分析 四. 快速排序的非递归实现 4.1 快速排序非递…

Promise详解与手写实现

Promise详解与手写实现Promise1、Promise介绍与基本使用1.1 Promise概述1.2 Promise的作用1.3 Promise的使用2、Promise API3、Promise关键问题4、Promise自定义封装5、async与await5.1. mdn文档5.2.async函数5.3.await表达式5.4.注意Promise 1、Promise介绍与基本使用 1.1 P…

电商维权,维权方法汇总【超全】

电商维权,就是维护线上渠道中自己的合法权益,其中包括消费者维权、品牌方维权、卖家维权。今天,我们来聊一聊消费者维权。 1、 维权类型 消费者在网购过程中难免遇到各种问题,主要就是产品质量问题、产品价格问题、产品售后问题、…

JavaWeb-VUEElement

JavaWeb-VUE&Element 1,VUE 1.1 概述 Vue 是一套前端框架,免除原生JavaScript中的DOM操作,简化书写。 Mybatis 是用来简化 jdbc 代码编写的;而 VUE 是前端的框架,是用来简化 JavaScript 代码编写的。前一天我们…

PID控制的方波响应

被控对象为一延迟对象:采样时间为20s,延迟时间为4个采样时间,即 80s,被控对象离散化为:y(k) -den(2)y(k- 1)num(2)u(k - 5)由于方波信号的速度、加速度不连续,当位置跟踪指令为方波信号时,如采用…

C++ 树进阶系列之树状数组的树形之路

1. 前言 树状数组也称二叉索引树,由Peter M. Fenwick于1994发明,也可称为Fenwick树。 树状数组的设计非常精巧,多用于求解数列的前缀和、区间和等问题,为区间类型问题提供了模板式解决方案。 数状数组简单易用,但对…

【100个 Unity实用技能】 | 修改Unity UI控件中默认字体配置

Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。Unity 平台提供一整套完善的软件解决方案&#xff…

【C++提高编程1】一文带你吃透函数模板和类模板(附测试用例源码、测试结果图及注释)

📝我的个人主页 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝​💬总结:希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🖊✉️今天你做别人不想做的事&…

域内权限维持:注入SSP

01、简介 SSP(Security Support Provider)是Windows操作系统安全机制的提供者。简单地说,SSP是个DLL文件,主要用来实现Windows操作系统的身份认证功能。在系统启动时,SSP 将被加载到lsass.exe进程中,攻击者通过自定义恶意的DLL文件…