文章目录
1.什么是Hough直线变换
一条直线可以用数学表达式 y = m x + c y = mx + c y=mx+c(斜截式) 或者 ρ \rho ρ = x c o s =x cos =xcos θ \theta θ + y s i n + y sin +ysin θ \theta θ(法线式) 表示。 ρ \rho ρ是从原点到直线的垂直距离, θ \theta θ是直线的垂线与横轴顺时针方向的夹角(OpenCV 坐标系)。如下图所示:
Hough变换检测形状的方法:
- 如果一条线在原点下方经过, ρ \rho ρ的值就应该大于0,角度小于180。但是如果从原点上方经过的话,角度可能大于180,也可能小于180,但 ρ \rho ρ的值小于0。垂直的线 θ \theta θ为0 度,水平线的 θ \theta θ为90 度。
- 图像上的每一条直线都可以用( ρ \rho ρ, θ \theta θ) 表示。可以创建一个2D 数组(accumulator),行表示 ρ \rho ρ,列表示 θ \theta θ,初始所有的值都为0。这个数组的大小决定了最后结果的准确性。如果你希望角度精确到1 度,你就需要180 列。对于 ρ \rho ρ,最大值为图片对角线的距离。所以如果精确度要达到一个像素的级别,行数就应该与图像对角线的距离相等。
- 如下图,有一个大小为100x100 的图像,有一条直线位于中央。取直线上的第一个点,我们知道此处的(x,y)值。把x 和y 带入上边的方程组,然后遍历 θ \theta θ的取值:0,1,2,3,…180。分别求出与其对应的 ρ \rho ρ的值,这样我们就得到一系列( ρ \rho ρ, θ \theta θ)的数值对,如果这个数值对在accumulator中也存在相应的位置,就在这个位置上加1。所以现在accumulator中的(50,90)=1。(一个点可能存在与多条直线中,所以对于直线上的每一个点可能是accumulator中的多个值同时加1)。
accumulator | 1° | 2° | … | 90° | … | 180° |
---|---|---|---|---|---|---|
1 | ||||||
… | ||||||
50 | 1 |
|||||
… | ||||||
142 |
- 现在取直线上的第二个点。重复上边的过程。更新accumulator中的值。现在accumulator中(50,90)的值为2。你每次做的就是更新accumulator中的值。对直线上的每个点都执行上边的操作,每次操作完成之后,accumulator中的值就加1,但其他地方有时会加1, 有时不会。按照这种方式下去,到最后accumulator中(50,90)的值肯定是最大的。如果你搜索accumulator中的最大值,并找到其位置(50,90),这就说明图像中有一条直线,这条直线到原点的距离为50,它的垂线与横轴的夹角为90 度。
2.opencv中的Hough直线变换
代码速记:
- cv2.HoughLines()
参数解释:
lines = cv2.HoughLines(edges,1,np.pi/180,200)
- 第一个参数是一个二值化图像,所以在进行霍夫变换之前要首先进行二值化,或者进行Canny 边缘检测。
- 第二和第三个值分别代表 ρ \rho ρ和 θ \theta θ 的精确度。
- 第四个参数是阈值,只有累加其中的值高于阈值时才被认为是一条直线,也可以把它看成能检测到的直线的最短长度(以像素点为单位)。
- 返回值就是( ρ \rho ρ, θ \theta θ )的列表。 ρ \rho ρ的单位是
像素
, θ \theta θ 的单位是弧度
。
实战:
已知 ρ \rho ρ = x c o s =x cos =xcos θ \theta θ + y s i n + y sin +ysin θ \theta θ,先求出 ρ \rho ρ和直线的垂点
处的坐标 ( x 0 , y 0 ) (x_0,y_0) (x0