python 霍夫直线变换_霍夫线变换

目录:一、引入极坐标

二、霍夫线变换实现原理

三、图像中的霍夫线变换

四、概率霍夫变换

五、Python 例子

六、参考

Hough线变换是一种用于检测直线的变换。它最大的优点是,即使是虚线(dashed line),或者某些部分缺失、被遮挡的直线,也能检测到完整的线条。

一、引入极坐标

我们经常在直角坐标系中用两个参数表示直线:

,其中 k 为斜率(slope),b为截距(intercept)。但是当直线趋近于垂直x轴时,k值会变得非常大(

)或非常小(

)以至于无法表示该直线。

所以对于霍夫线变换,常在极坐标中表示一条直线:

直线在极坐标系下的表达式为:

由该图可以看出直线表达式是如何形成的

(x, y)为直角坐标系中的一个点A,这个表达式就表示经过点(x, y)的所有直线,每条直线所对应的

​ 都不相同。

这里

表示原点到直线的距离,以像素为单位;

是这条垂直线和水平轴形成的角度。

所以图像空间的每一个像素点都对应一个这样的正弦表达式。

二、霍夫线变换实现原理

2.1、对于某个点

,我们可以将穿过该点的所有直线的集合定义为:

这意味着其中的每对

都表示经过

的一条直线。

2.2、给定一个点

,我们会得到过该点的一系列直线,将这些直线对应的参数

值画在

平面中,我们可以得到一条正弦曲线(只考虑

的点。):

上面是经过点(8, 6)的所有直线的极坐标表达式中的

参数所构成的曲线。

3.3、我们可以对其他的点进行相同的操作,按照上面的例子,画出另外两点

的曲线图:

如果两个不同点所对应的曲线在平面

中相交,就意味着两个点属于同一条直线,因为它们有相同的

参数。

如上图所示,这三条曲线相交于点(0.925,9.6),这是参数

的值,表示

都在这两个参数值所决定的直线上。

我们把

平面看做霍夫空间,

就是该空间中的点。而极坐标中的一个点就对应霍夫空间中的一条曲线。

三、图像中的霍夫线变换

知道了霍夫线变换的实现原理,怎么应用于检测图像中的直线呢?上面提到的点在图像中是对应哪些点呢?

进行霍夫线变换之前需要先对图像进行canny边缘检测得到二值图,将这个二值图进行霍夫线变换。

我们知道这个二值图除了图像中的边缘像素,其他像素的灰度值都为零,即表现黑色。而我们就是要根据这些非零灰度值的像素点(边缘像素),来获取在

平面中的曲线。

就是根据每个边缘像素(x,y),我们将

的值从0更改为

,根据公式

,获得对应的

值。从而获取所有边缘像素在

平面的曲线。

得到每个边缘像素的曲线后,通过计算

平面中各交点所在的曲线数量来检测直线。某点相交的曲线越多,意味着该交点所表示的直线具有越多的点,即在图像中直线越长。

我们还可以定义阈值,在某点相交的曲线数量大于该阈值,才认为该点在图像中对应一条直线。

所以要理解霍夫变换最关键的一点就是:

极坐标的点(

-

平面) <=> 直角坐标系中的曲线(

-

平面)

即在图像中一个边缘像素点,经过霍夫变换,变成霍夫空间(

-

平面)中的一条正弦曲线。

四、概率霍夫变换

上面介绍的标准霍夫变换,其本质上就是把图像中的边缘像素映射到它的霍夫空间,比如一共有M个边缘像素,则所有的边缘像素都需要进行映射,其运算量和所需内存都会很大。

如果只处理图像的m(m

下面是概率霍夫变换的简易步骤:随机抽取图像中的一个边缘像素点,如果已经被标定为是某一条直线上的点,则继续在剩下的边缘点中随机抽取一个边缘点,直到所有边缘点都抽取完为止;

对该点进行霍夫变换,并进行累加计算;

选取在霍夫空间内累加值最大的点,如果该点的值大于阈值,则进行步骤4,否则回到步骤1;

对于累加值大于阈值的点,从该点出发,沿着图像中的直线的方向位移,从而找到直线的两个端点;

计算直线的长度,如果大于某个阈值,则被认为是直线并输出。

五、Python 例子

OpenCV 中有霍夫线变换的API,我们直接调用即可。

原图为:白底黑线

我这里用的概率霍夫线变换函数:

HoughLinesP(image, rho, theta, threshold)image:二值图(边缘检测器的输出);

rho:距离分辨率,以像素为单位;

theta:角度分辨率,单位为弧度;

threshold:交点的最小曲线数量大于阈值,才被视为一条直线。

maxLineGap:这是一个可选参数,表示两个线段之间的gap小于该值,则进行连接

import cv2

import numpy as np

img = cv2.imread("/home/zxd/Pictures/lines.jpg")

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# detecting the edges

edges = cv2.Canny(gray, 50, 200)

# apply probabilistic hough transform for line detection

lines = cv2.HoughLinesP(edges, 1, np.pi/180, 30)

# maxLineGap 参数的值为200,则线之间的gap小于200像素就将其进行连接

lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=30, maxLineGap=200)

# 得到所有线段的端点

for line in lines:

x1, y1, x2, y2 = line[0]

cv2.line(img, (x1, y1), (x2, y2), (0,0,255))

cv2.imshow('img', img)

if cv2.waitKey(0) == ord('q'):

cv2.destroyAllWindows()

下面是输出的结果:

两者分别为不使用 maxLineGap 参数和使用 maxLineGap 参数的结果图。

所以即使遇到虚线或者被遮挡的直线,我们也可以使用霍夫线变换来进行直线检测。

六、参考

如果觉得有用,点个赞吧(ง •̀_•́)ง。

你可能感兴趣的:(python,霍夫直线变换)