Python OpenCV 霍夫(Hough Transform)直线变换检测原理,图像处理第 33 篇博客

Python OpenCV 365 天学习计划,与橡皮擦一起进入图像领域吧。本篇博客是这个系列的第 33 篇。

基础知识铺垫

霍夫变换(Hough Transform)是图像处理领域中,从图像中识别几何形状的基本方法之一。主要识别具有某些相同特征的几何形状,例如直线,圆形,本篇博客的目标就是从黑白图像中识别出直线。

翻阅霍夫直线变换的原理时候,橡皮擦觉得原理部分需要先略过,否则很容易在这个地方陷进去,但是问题来了,这个原理略过了,直接应用函数,里面有些参数竟然看不懂。例如极坐标,角度扫描范围,这种函数就属于绕不过去的知识点了,所以本文转移方向,死磕原理,下面的博文将语无伦次的为你展示如何学习原理知识。

霍夫变换直线检测的基本原理

因为数学知识的贫乏,所以在学习阶段会涉及到很多基础概念的学习,一起来吧。

首先找到相对官方的资料,打开该 地址

下面是一个数学小白对原理的学习经验。

教材说:众所周知,一条直线在图像二维空间可由两个变量表示。

  • 在笛卡尔坐标系:可由参数: (m,b) 斜率和截距表示;
  • 在极坐标系: 可由参数: (r,θ) 极径和极角表示。

抱歉,小白还真不知道……即使学习过,这些年也早已经还给老师了。

一开始难道要学习笛卡尔坐标系,不,你低估小白的能力了,我第一个查询的是 θ 读作 西塔,是一个希腊字母。

什么是笛卡尔坐标系?

这个比较简单,直角坐标系。

斜率和截距

斜率,亦称“角系数”,表示一条直线相对于横坐标轴的倾斜程度。

一条直线与某平面直角坐标系横坐标轴正半轴方向的夹角的正切值即该直线相对于该坐标系的斜率。

如果直线与 x 轴互相垂直,直角的正切直无穷大,故此直线不存在斜率。
对于一次函数 y=kx+bk 就是该函数图像的斜率。

在学习的时候,也学到如下内容:

截距:对 x 的截距就是 y=0 时,x 的值,对 y 的截距就是 x=0 时,y 的值,
截距就是直线与坐标轴的交点的横(纵)坐标。x 截距为 ay 截距 b,截距式就是:x/a+y/b=1(a≠0且b≠0)

斜率:对于任意函数上任意一点,其斜率等于其切线与 x 轴正方向所成的角,即 k=tanαax+by+c=0中,k=-a/b

需要注意的是:斜率不能不存在或等于 0,因为当斜率不存在时,直线垂直于 X 轴,没有纵截距,当斜率等于 0 时,直线平行于 X 轴,没有横截距。

什么是极坐标系?

关于极坐标系,打开 百度百科 学习一下即可。

重点学到下面这个结论就行:

有序数对(θ,ρ)就称为 P 点的极坐标,记为 P(θ,ρ);p 称为 P 点的极径,θ 称为 P 点的极角。

找资料的时候,发现一个解释的比较清楚的 博客,后续可以继续学习使用。

继续阅读资料,看到如下所示的图,这个图也出现在了很多解释原理的博客里面,但是图下面写了一句话
Python OpenCV 霍夫(Hough Transform)直线变换检测原理,图像处理第 33 篇博客

对于霍夫变换, 我们将用 极坐标系 来表示直线. 因此, 直线的表达式可为:
y = ( − cos ⁡ θ sin ⁡ θ ) x + ( r sin ⁡ θ ) y = \left ( -\dfrac{\cos \theta}{\sin \theta} \right ) x + \left ( \dfrac{r}{\sin \theta} \right ) y=(sinθcosθ)x+(sinθr)

在这里直接蒙掉了,怎么就表示成极坐标系了?上面这个公式依旧是笛卡尔坐标系表示直线的方式呀,只是把 kb 的值给替换掉了。

y = − k x + b y = -kx + b y=kx+b
其中 − k = ( − cos ⁡ θ sin ⁡ θ ) -k=\left(-\dfrac{\cos \theta}{\sin \theta} \right) k=(sinθcosθ) b = ( r sin ⁡ θ ) b=\left ( \dfrac{r}{\sin \theta} \right ) b=(sinθr)
这还是笛卡尔坐标系呀,不是极坐标系。

为何是这样的,具体原因可以参照下图。

Python OpenCV 霍夫(Hough Transform)直线变换检测原理,图像处理第 33 篇博客

chou 图

霍夫空间

继续寻找关于霍夫变换的资料,找到一个新的概念霍夫空间

在笛卡尔坐标系中,一条直线可以用公式 y = k x + q y = kx+q y=kx+q 表示,其中 kb 是参数,表示的是斜率和截距。

接下来将方程改写为 b = − k ∗ x 0 + y 0 b=-k*x_0+y_0 b=kx0+y0,这时就建立了一个基于 k - b 的笛卡尔坐标系。

此时这个新的方程在 k - b 坐标系也有一个新的直线。

你可以在纸上画出这两个方程对应的线和点,如下图所示即可。

Python OpenCV 霍夫(Hough Transform)直线变换检测原理,图像处理第 33 篇博客

chou 图

新的 k - b 坐标系就叫做霍夫空间,这时得到一个结论,图像空间 x - y 中的点 A ( x 0 , y 0 ) A(x_0,y_0) A(x0,y0) 对应了霍夫空间 k - b 中的一条直线 b = − k ∗ x 0 + y 0 b = -k*x_0+y_0 b=kx0+y0,即图像空间的点与霍夫空间的直线发生了对应关系。

如果在图像空间 x - y 中在增加一个点 B ( x 0 , y 0 ) B(x_0,y_0) B(x0,y0),那相应的该点在霍夫空间也会产生相同的点与线的对应关系,并且 A 点与 B 点产生的直线会在霍夫空间相交于一个点。而这个点的坐标值 ( k 0 , b 0 ) (k_0,b_0) (k0,b0) 就是直线 AB 的参数。

如果到这里你掌握了,这个性质就为我们解决直线检测提供了方法,只需要把图像空间的直线对应到霍夫空间的点,然后统计交点就可以达到目的,例如图像空间中有 3 条直线,那对应到霍夫空间就会有 3 个峰值点。

遍历图像空间中的所有点,将点转换到霍夫空间,形成大量直线,然后统计出直线交会的点,每个点的坐标都是图像空间直线方程参数,这时就能得到图像空间的直线了。

上述的内容没有问题,但是存在一种情况是,当直线趋近于垂直时,斜率 k 会趋近于无穷大,这时就没有办法转换了,解决办法是使用法线来表示直线。

完善霍夫空间

上文提及的斜截式如下:

y = − k x + b y = -kx + b y=kx+b
其中 − k = ( − cos ⁡ θ sin ⁡ θ ) -k=\left(-\dfrac{\cos \theta}{\sin \theta} \right) k=(sinθcosθ) b = ( r sin ⁡ θ ) b=\left ( \dfrac{r}{\sin \theta} \right ) b=(sinθr)

通过第二个公式,可以得到下述公式:

ρ = x ⋅ cos ⁡ θ + y ⋅ sin ⁡ θ ρ = x \cdot \cos \theta + y \cdot \sin \theta ρ=xcosθ+ysinθ

此时,我们可以带入一些数值进行转换。

图像空间有如下的几个点:

  • ( 1 , 0 ) (1,0) (1,0),通过 p = x cos ⁡ θ + y sin ⁡ θ p = x \cos \theta + y \sin \theta p=xcosθ+ysinθ 转换为 p = cos ⁡ θ p=\cos \theta p=cosθ
  • ( 2 , 2 ) (2,2) (2,2),通过 p = x cos ⁡ θ + y sin ⁡ θ p = x \cos \theta + y \sin \theta p=xcosθ+ysinθ 转换为 p = 2 cos ⁡ θ + 2 sin ⁡ θ p=2\cos \theta +2\sin\theta p=2cosθ+2sinθ
  • ( 3 , 2 ) (3,2) (3,2),通过 p = x cos ⁡ θ + y sin ⁡ θ p = x \cos \theta + y \sin \theta p=xcosθ+ysinθ 转换为 p = 3 cos ⁡ θ + 2 sin ⁡ θ p=3\cos \theta +2\sin\theta p=3cosθ+2sinθ

转换后的函数,都可以在霍夫空间 θ - ρ(横坐标是 θ,纵坐标是 ρ)进行表示。

原理这时就比较清晰了:

一条直线能够通过在平面 θ - rr 就是本文中的 ρ) 寻找交于一点的曲线数量来检测。
越多曲线交于一点也就意味着这个交点表示的直线由更多的点组成。
一般来说我们可以通过设置直线上点的阈值来定义多少条曲线交于一点我们才认为检测到了一条直线。

相关数学知识挖坑

除了一些数学知识以外,经典的博客我们也有必要记录一下,方便后面学习的时候,进行复盘。

  • https://blog.csdn.net/yuyuntan/article/details/80141392
  • https://blog.csdn.net/leonardohaig/article/details/87907462

本部分用于记录本文中提及的相关数学原理,后续还要逐步埋坑。

  • 直线方程,点斜式、截距式、斜截式、两点式、法线式等内容;
  • 正弦曲线。

橡皮擦的小节

今天涉及了一点点数学知识,能力限制,大家一起学习,有错误的地方,可以在评论区指出,不胜感激。

希望今天的 1 个小时(今天内容有点多,不一定可以看完),你有所收获,我们下篇博客见~

相关阅读


技术专栏

  1. Python 爬虫 100 例教程,超棒的爬虫教程,立即订阅吧
  2. Python 爬虫小课,精彩 9 讲

逗趣程序员

  1. 曝光,程序员的 10 个摸鱼神器
  2. 5 个无聊 Python 程序,用 Python 整蛊你的朋友们吧
  3. 10 年老程序员教你甩锅必杀技,论【如何优雅的甩锅】
  4. 你想被开除吗?来看看程序员【离职小技巧】吧

今天是持续写作的第 74 / 100 天。
如果你有想要交流的想法、技术,欢迎在评论区留言。


如果你想跟博主建立亲密关系,可以关注同名公众号 梦想橡皮擦,近距离接触一个逗趣的互联网高级网虫。
博主 ID:梦想橡皮擦,希望大家点赞评论收藏

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦想橡皮擦

如有帮助,来瓶可乐

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值