OpenCV学习(4.13) 霍夫变换

1.霍夫变换

霍夫变换(Hough Transform)是图像处理中的一种技术,主要用于检测图像中的直线、圆或其他形状。它通过将图像空间中的点映射到参数空间来实现,这样,图像空间中在同一直线上的点在参数空间中会形成一条曲线,而这条曲线上的交点对应于图像空间中的直线。
霍夫变换的基本思想是:

  1. 对于图像中的每一个边缘点,考虑它可能属于的所有候选直线。
  2. 对于每一条候选直线,使用霍夫变换算法在参数空间中对其进行投票。
  3. 投票最多的候选直线即为检测到的直线。

霍夫变换有几种变体,包括:

  • - 霍夫直线变换:用于检测图像中的直线。
  • - 霍夫圆变换:用于检测图像中的圆。
  • - 霍夫椭圆变换:用于检测图像中的椭圆。

霍夫变换的优点是它对噪声和图像间断有一定的鲁棒性,但缺点是计算量大,特别是对于霍夫圆变换,因为需要考虑三个参数(圆心坐标和半径)。因此,在实际应用中,通常会采用一些优化技术来减少计算量,例如使用图像金字塔或限制参数范围。

2. 霍夫线变换

在这一章当中,

  • 我们将理解霍夫变换的概念。
  • 我们将看到如何使用它来检测图像中的线条。
  • 我们将了解以下函数: cv.HoughLines() , cv.HoughLinesP()

如果您能够以数学形式表示该形状,则霍夫变换是一种用于检测任何形状的流行技术。它可以检测到形状,即使它被破坏或扭曲一点点。我们将看到它如何适用于生产线。

一条线可以表示为 $$y = mx+c$$ 或以极坐标形式 $$\rho = x \cos \theta + y \sin \theta$$ 表示为其中 $$\rho$$ 是垂线从原点到直线的距离。$$\theta$$ 是这条垂直线形成的角度,水平轴是逆时针测量的(该方向因你代表坐标系而变化。这种表示用于 OpenCV )。检查下图:

所以如果这条线经过原点以下,它会有一个小于 180 度的正角度。如果它在原点上方,我们不是取一个大于 180 的角,而是取一个小于 180 的负角度。任何垂直线都是 0 度,水平线是 90 度。

现在我们来看看霍夫变换是怎么作用于直线的。任何线都可以被表示成这两项(r,θ) 。所以首先它创建了一个二维数组,或者是累加器(来保存这两个参数的值)然后他设置(r,θ) 作为初始值。 令(二维数组的)行表示r,令列表示 θ 。数组的大小取决于你需要的精准度。假设说你想要角度的精度是精确到 1 度,那你就需要 180 列。而对于r来说,最大可能的距离是图像的对角线长度。因此,要精确到一个像素的程度,行数应该是图像的对角长度。

想象有一张 100x100 的图像,它上面有一条水平的线条在图像正中间。取这条线的第一个点,你知道它的坐标 (x,y)值。现在,按照这条直线的等式,把值​​​​​​​θ = 0,1,2,...,180带入,并且查看你获取到的r值。对每一对​​​​​​​(r,θ) ,我们都把它们在累加器中对应的值计数增加 1。而此时,在这个计数器中,单元 (50,90) 和其他单元一样计数等于 1。

现在去这条线上的第二个点,重复上面的步骤。增加单元中你拿到的对应的值(rho, theta)。这一次,单元(50,90)的计数增到到了 2。你实际上做的是投票投出​​​​​​​(r,θ) 值。你不断为这条直线上所有的点继续这个过程。在每一个点,单元(50,90)都会得票,而其他的单元有可能会得票,也有可能不会。按这个方案,最终单元 (50,90) 会获得最高的投票(译者注:在 100X100 的图像正中水平的直线到原点距离为 50,垂角 90 度)。所以最终搜索我们的累加器来找最高得票的单元,我们就会取到 (50,90),这就说明图像中有一条线距离原点垂距 50,它过原点的垂线和水平线夹角为 90 度。这个过程很好的显示在了以下的动画中

这就是霍夫变化针对直线工作的原理。非常简单,也许你可以用 Numpy 自己来实现它。以下是一张显示了累加器的图像。在某些地方的亮点说明它们是图像中可能线条的参数。 

 

2. 1 OpenCV中的霍夫变换

上面解释的这一堆东西,在 OpenCV 里都封装起来成为**cv.HoughLines()** 函数了。它简单的返回了一个(rho, theta)`值得数组。$$\rho$$ 的单位是像素,$$\theta$$的单位是弧度。第一个参数,输入图像应该是个二元图像,所以在应用霍夫线性变换之前先来个阈值法或者坎尼边缘检测。第二、第三参数分别是 $$\rho$$ 和 $$\theta$$ 的精度。第四个参数则是一个阈值,它代表了一个$$(\rho,\theta)$$单元被认为是一条直线需要获得的最低票数。要记住的是,得票数其实取决于这条直线穿过了多少个点。所以它也代表了应被检测出的线条最少有多长。

霍夫变换作用于直线的过程通常指的是霍夫直线变换(Hough Line Transform),它是一种在数字图像中检测直线的常用技术。霍夫直线变换的基本思想是将图像空间中的直线映射到参数空间中的点上,从而将直线检测问题转化为在参数空间中寻找交点的问题。
霍夫直线变换的具体步骤如下:
1. **边缘检测**:首先,使用边缘检测算法(如Canny边缘检测)找到图像中的边缘像素。
2. **参数空间投票**:对于每个边缘像素,考虑所有可能的直线方程,通常是直线方程的极坐标形式:\( r = x \cos(\theta) + y \sin(\theta) \),其中 \( (r, \theta) \) 是参数空间中的点,\( (x, y) \) 是图像空间中的边缘像素坐标。对于每个 \( (x, y) \) ,在参数空间中画出对应的所有 \( (r, \theta) \) 曲线。
3. **累加和阈值**:在参数空间中,对于每个可能的 \( (r, \theta) \) 对,累加器数组中的一个单元被增加。当多个边缘像素对应的曲线在参数空间中相交于同一点时,该点的累加器值会很高。
4. **检测峰值**:在累加器数组中,峰值对应于图像中的直线。设置一个阈值,只有超过这个阈值的累加器值才被认为是检测到的直线。
5. **提取直线**:对于每个检测到的峰值,其对应的 \( (r, \theta) \) 值可以用来确定图像空间中的一条直线。
霍夫直线变换的优点是它对图像中的直线断裂和噪声不敏感,能够检测出图像中所有的直线,无论其方向如何。然而,这种方法的一个缺点是计算量大,特别是对于高分辨率图像。此外,它通常只适用于检测直线,而不适用于检测曲线或其他复杂的形状。对于这些情况,需要使用霍夫变换的其他变体,如霍夫圆变换或广义霍夫变换。
 

import cv2 as cv
import numpy as np
img = cv.imread(cv.samples.findFile('sudoku.png'))
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150,apertureSize = 3)
lines = cv.HoughLines(edges,1,np.pi/180,200)
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))
    cv.line(img,(x1,y1),(x2,y2),(0,0,255),2)
cv.imwrite('houghlines3.jpg',img)

检查以下结果: 

2.2 概率Hough变换 

概率Hough变换(Probabilistic Hough Transform)是标准Hough变换的一种改进版本,它用于检测图像中的直线,但是相比于标准Hough变换,它更加高效,因为它不需要遍历整个参数空间。概率Hough变换通过随机选择图像空间中的边缘点,并只考虑这些点对应的参数空间中的少量可能直线,从而减少了计算量。
概率Hough变换的基本步骤如下:
1. **边缘检测**:与标准Hough变换一样,首先使用边缘检测算法找到图像中的边缘像素。
2. **随机采样**:从检测到的边缘点中随机选择一个点。
3. **局部峰值搜索**:对于选中的边缘点,在参数空间中搜索其可能的直线参数。这一步通常是通过在较小的邻域内进行累加器投票来实现的。
4. **累加器阈值**:如果参数空间中的某个局部区域的累加器值超过了设定的阈值,则认为找到了一条直线。
5. **重复过程**:重复步骤2到4,直到所有的边缘点都被考虑过,或者达到了某种停止条件(如找到了足够的直线)。
6. **结果验证**:最后,可能需要对检测到的直线进行验证,以确保它们是真实的直线,而不是由噪声或错误的边缘检测引起的假阳性。

概率Hough变换相比于标准Hough变换的优点是它更快,因为它不需要为每个边缘点计算和投票所有的参数空间。此外,它通常能够给出更准确的结果,因为它考虑了边缘点之间的局部关系。这种方法的缺点是它可能不会检测到图像中所有的直线,特别是当直线的支持点较少时。因此,概率Hough变换适用于直线较为密集的场景,而在直线稀疏的情况下可能不如标准Hough变换有效。

在霍夫变换中,你可以发现即使是一条仅有两个参数的直线,也需要用到大量的计算。概率霍夫变换是我们已知的,针对霍夫变换的优化方案。它不去取所有的点来列入考虑,取而代之的是取足够完成直线检测的这些点的随机子集。只要我们把阈值下调一点。下图在霍夫空间中比较了霍夫变换与概率霍夫变换。

OpenCV 实现基于使用 Matas,J。和 Galambos,C。和 Kittler,J.V。 [133] 的渐进概率 Hough 变换的线的鲁棒检测。使用的函数是 cv.HoughLinesP() 。它比之前介绍的函数多出来两个参数:

  • minLineLength - 最小线长。比这个值小的线条会被丢弃。
  • maxLineGap - 允许线段之间的最大间隙,以便将(在同一条直线上的)线段视为同一条。

最好的是,它直接返回直线的两个端点。在前面的例子中,你只得到直线的参数,你必须找到所有的点。而这个方法,一切都是那么的直接和简单。

import cv2 as cv
import numpy as np
img = cv.imread(cv.samples.findFile('sudoku.png'))
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150,apertureSize = 3)
lines = cv.HoughLinesP(edges,1,np.pi/180,100,minLineLength=100,maxLineGap=10)
for line in lines:
    x1,y1,x2,y2 = line[0]
    cv.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv.imwrite('houghlines5.jpg',img)

 

3. 霍夫圆变换 

在这一章当中,

  • 我们将学习使用霍夫变换来查找图像中的圆圈。
  • 我们将了解这些函数: cv.HoughCircles()

圆圈在数学上表示为$(x-x_{center})^2 + (y - y_{center})^2 = r^2$其中$(x_{center},y_{center})$是圆的中心,$r$ 是圆的半径。从这个公式来看,得知我们有三个参数,这样我们就需要一个三维度的累加器来做霍夫变换了,这样效率是非常低的。所以 OpenCV 用了更巧妙的方法Hough Gradient Method ,它利用了边缘的梯度信息。

霍夫圆变换(Hough Circle Transform)是霍夫变换的一种变体,专门用于检测图像中的圆。与霍夫直线变换不同,霍夫圆变换需要检测三个参数:圆心坐标 \( (x, y) \) 和半径 \( r \)。这导致参数空间成为三维的,因此计算量相对较大。
霍夫圆变换的基本步骤如下:

  • 1. **图像预处理**:首先对图像进行滤波和边缘检测,以突出圆的特征。
  • 2. **参数空间投票**:对于每个边缘点,考虑所有可能的半径大小,对于每个可能的半径,计算圆心可能的位置,并在三维参数空间中对应的 \( (x, y, r) \) 处进行投票。
  • 3. **累加和峰值检测**:在参数空间中,累加器数组中的值表示找到圆的可能性。累加器数组中的局部峰值对应于图像中的圆。设置一个阈值,只有超过这个阈值的累加器值才被认为是检测到的圆。
  • 4. **提取圆心和半径**:对于每个检测到的峰值,其对应的 \( (x, y, r) \) 值可以用来确定图像空间中的一个圆。

由于霍夫圆变换的计算量很大,实际应用中通常会采用一些启发式方法来减少搜索空间,例如限制半径的范围或使用图像金字塔进行多尺度检测。
霍夫圆变换的优点是它对图像中的圆具有一定的鲁棒性,即使圆不完整或存在一定的噪声也能检测出来。然而,它的计算量大,且对噪声敏感,因此在实际应用中需要根据具体情况选择合适的参数和预处理步骤。
 

我们在这里使用的函数是 cv.HoughCircles() 。它的参数非常的多,这些参数在文档中都有详细的解释。所以我们直接上代码吧。

import numpy as np
import cv2 as cv
img = cv.imread('opencv-logo-white.png',0)
img = cv.medianBlur(img,5)
cimg = cv.cvtColor(img,cv.COLOR_GRAY2BGR)
circles = cv.HoughCircles(img,cv.HOUGH_GRADIENT,1,20,
                            param1=50,param2=30,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
    # draw the outer circle
    cv.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
    # draw the center of the circle
    cv.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv.imshow('detected circles',cimg)
cv.waitKey(0)
cv.destroyAllWindows()

结果如下图所示:

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CentOS系统自带Python2无法使用pip命令

Linux运维工具-ywtool 目录 一. 系统环境二.解决三.验证四.备注(1)输入"yum install -y python-pip",提示没有可用 python-pip包(2)安装完pip后进行升级 一. 系统环境 centos7系统自带的python2.7无法使用pip命令 二.解决 yum install python-pip -y三.验证 pip…

用PlayCanvas打造一个3D模型

本文由ScriptEcho平台提供技术支持 项目地址:传送门 基于 PlayCanvas 的 3D 物理场景开发 应用场景介绍 PlayCanvas 是一款功能强大的 3D 引擎,可用于创建各种类型的 3D 体验,包括游戏、模拟和交互式可视化。本技术博客将介绍如何使用 Pl…

【ARM Cache 及 MMU 系列文章 6.2 -- ARMv8/v9 如何读取 Cache 内部数据并对其进行解析?】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 Direct access to internal memoryL1 cache encodingsL1 Cache Data 寄存器Cache 数据读取代码实现测试结果Direct access to internal memory 在ARMv8架构中,缓存(Cache)是用来加…

企业中的绩效管理

背景 企业中为何需要绩效管理,企业绩效管理为何比较难,这在企业管理中是非常难,同样也是非常有价值的命题,那么首先应该对这个命题有清晰的认知,特别是要想明白为何企业需要绩效管理,应该先明白企业。 企…

2024 年 19 种最佳大型语言模型

大型语言模型是 2023 年生成式人工智能热潮背后的推动力。然而,它们已经存在了一段时间了。 LLM是黑盒 AI 系统,它使用深度学习对超大数据集进行处理,以理解和生成新文本。现代 LLM 开始成型于 2014 年,当时一篇题为“通过联合学…

妙用OSGraph:发掘GitHub知识图谱上的开源故事

作者:范志东 1. 何为OSGraph? OSGraph (Open Source Graph) 是一个开源图谱关系洞察工具,基于GitHub开源数据全域图谱,实现开发者行为、项目社区生态的分析洞察。可以为开发者、项目Owner、开源布道师、社区运营等提供简洁直观的…

手机如何扫描拍照?方法分享

手机如何扫描拍照?在数字化时代,手机扫描拍照软件已经成为我们日常生活和工作中不可或缺的工具。无论是快速识别纸质文档,还是将照片中的文字转化为可编辑的文本,这些软件都为我们提供了极大的便利。然而,市面上的手机…

msvcp110.dll有什么解决方案,msvcp110.dll几种方法详细步骤教程

本文旨在探讨如何应对电脑出现 vcruntime140_1.dll 无法继续执行代码错误提示的问题。同时,将阐释该文件的作用,列举常见的错误问题,并提供一些在修复 vcruntime140_1.dll 时的注意事项,以避免在解决过程中引发其他问题。接下来&a…

【网络安全】【深度学习】【入侵检测】SDN模拟网络入侵攻击并检测,实时检测,深度学习【一】

文章目录 1. 前言2. Mininet 和 Ryu 的区别2.1 Mininet2.2 Ryu2.3 总结 3. 模拟攻击3.1 环境准备3.2 创建 Mininet 网络拓扑3.2 启动 Ryu 控制器3.3 模拟网络攻击3.4 捕获流量 4. 实时异常检测4.1 在 Ryu 控制器中4.2 在 h2 机器上的实验结果4.3 深度学习模型部署上h2机器 帮助…

如何获知lib cell的用途

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 除了databook可以查询cell的用途外,还可以通过在pr工具中获取lib cell属性的方法知晓其用途。 ICC2: report_attribute -app -class lib_cell SDFFXXX 通过看is_…

【大数据】计算引擎:Spark核心概念

目录 前言 1.什么是Spark 2.核心概念 2.1.Spark如何拉高计算性能 2.2.RDD 2.3.Stage 3.运行流程 前言 本文是作者大数据系列中的一文,专栏地址: https://blog.csdn.net/joker_zjn/category_12631789.html?spm1001.2014.3001.5482 该系列会成体…

【递归、搜索与回溯】综合练习一

综合练习一 1.找出所有子集的异或总和再求和2.全排列 II3.电话号码的字母组合4.括号生成 点赞👍👍收藏🌟🌟关注💖💖 你的支持是对我最大的鼓励,我们一起努力吧!😃😃 1.找…

2024年【四川省安全员C证】免费试题及四川省安全员C证考试技巧

题库来源:安全生产模拟考试一点通公众号小程序 四川省安全员C证免费试题是安全生产模拟考试一点通总题库中生成的一套四川省安全员C证考试技巧,安全生产模拟考试一点通上四川省安全员C证作业手机同步练习。2024年【四川省安全员C证】免费试题及四川省安…

linux搭建sftp服务

1. 添加用户及用户组 使用 groupadd sftpgroup 添加sftpgroup 用户组; 使用useradd -G sftpgroup -s /sbin/nologin cmssftp给sftpgroup 添加cmssftp用户; 使用passwd cmssftp给用户cmssftp进行设置密码(默认为:654321)。具体如下图所示: 2.…

云原生Kubernetes系列项目实战-k8s集群+高可用负载均衡层+防火墙

一、Kubernetes 区域可采用 Kubeadm 方式进行安装: 名称主机部署服务master192.168.91.10docker、kubeadm、kubelet、kubectl、flannelnode01192.168.91.11docker、kubeadm、kubelet、kubectl、flannelnode02192.168.91.20docker、kubeadm、kubelet、kubectl、flan…

文心一言 VS 讯飞星火 VS chatgpt (280)-- 算法导论20.4 1题

一、假设 CONNECTED-COMPONENTS 作用于一个无向图 G(V,E),这里V{a,b,c,d,e,f,g,h,i,j,k},且 E 中的边以如下的顺序处理:(d…

在Lua解释器中注册自定义函数库

本文目录 1、引言2、注册原理3、实例4、程序验证 文章对应视频教程: 暂无,可以关注我的B站账号等待更新。 点击图片或链接访问我的B站主页~~~ 1、引言 在现代软件开发中,Lua因其轻量级、高效和可嵌入性而被广泛使用。作为一种灵活的脚本语言…

使用uniapp设置tabbar的角标和移除tabbar的角标

使用场景描述 在一进入到小程序的时候就要将用户在购物车中添加的商品总数&#xff0c;要以角标的形式显示在tababr中。 代码实现 //index.vue<script setup> import { onLoad } from dcloudio/uni-apponLoad(()>{uni.setTabBarBadge({index: 1,text: 5 //为了实现…

电商开发者必读:微店商品详情API接口全解析

微店作为一个流行的电商平台&#xff0c;提供了丰富的API接口供开发者使用。详细介绍商品详情API接口的使用方法&#xff0c;帮助开发者快速获取商品信息&#xff0c;实现商品信息的自动化展示和管理。 1. 接口简介 微店商品详情API接口允许开发者通过商品ID获取商品的详细信…

如何使用 Midjourney换脸,将一个人面部复制并粘贴到任意人身上

嘿&#xff0c;想不想将一个人的面部随意粘贴到任意人身上&#xff1f;现在开始教学如何使用 Discord 中的Midjourney Bot 实现&#xff0c;这就是“COPY A FACE”这个超酷的功能&#xff0c;它能帮你一键把脸贴到任何图片上。用到的是一个叫“InsightFace”的开源Discord机器人…