史上最详细的Hough直线检测

之前写过检测车道线的文章:https://blog.csdn.net/u010712012/article/details/84780943
最后可以检测出两条车道线,但是,本课题的目的是通过提供一张图片,经过图像处理操作,经过算法模型得到违章的车辆情况,所以不能有人为的因素。

所以这里再次回顾一下检测直线的算法之——Hough变换。

Hough直线检测

1.直线坐标参数空间

在图像x−y坐标空间中,经过点( x i x_{i} xi, y i y_{i} yi)的直线表示为:
y i = a x i + b − − − − − ( 1 ) y_{i}=ax_{i}+b -----(1) yi=axi+b(1)
其中,参数a为斜率,b为截矩。
通过点( x i x_{i} xi, y i y_{i} yi)的直线有无数条,且对应于不同的a和b值。

如果将 x i x_{i} xi y i y_{i} yi视为常数,而将原本的参数a和b看作变量,则式子(1)可以表示为:
b = − x i a + y i − − − − − ( 2 ) b=−x_{i}a+y_{i}-----(2) b=xia+yi(2)

这样就变换到了参数平面a−b。这个变换就是直角坐标中对于( x i x_{i} xi, y i y_{i} yi)点的Hough变换。

该直线是图像坐标空间中的点( x i x_{i} xi, y i y_{i} yi)在参数空间的唯一方程。考虑到图像坐标空间中的另一坐标( x j x_{j} xj, y j y_{j} yj),它在参数空间中也有相应的一条直线,表示为:

b = − x j a + y j − − − − − ( 3 ) b=−x_{j}a+y_{j}-----(3) b=xja+yj(3)

这条直线与点( x i x_{i} xi, y i y_{i} yi)在参数空间的直线相交于一点( a 0 a_{0} a0, b 0 b_{0} b0),如图所示:

史上最详细的Hough直线检测_第1张图片
图像坐标空间中过点( x i x_{i} xi, y i y_{i} yi)和点( x j x_{j} xj, y j y_{j} yj)的直线上的每一点在参数空间a−b上各自对应一条直线,这些直线都相交于点 ( a 0 , b 0 ) (a_{0},b_{0}) (a0,b0),而a0、b0就是图像坐标空间x−y中点( x i x_{i} xi, y i y_{i} yi))和点( x j x_{j} xj, y j y_{j} yj)所确定的直线的参数。

反之,在参数空间相交于同一点的所有直线,在图像坐标空间都有共线的点与之对应。根据这个特性,给定图像坐标空间的一些边缘点,就可以通过Hough变换确定连接这些点的直线方程。

具体计算时,可以将参数空间视为离散的。建立一个二维累加数组A(a,b),第一维的范围是图像坐标空间中直线斜率的可能范围,第二维的范围是图像坐标空间中直线截矩的可能范围。开始时A(a,b)初始化为0,然后对图像坐标空间的每一个前景点(xi,yi),将参数空间中每一个a的离散值代入式子(2)中,从而计算出对应的b值。每计算出一对(a,b),都将对应的数组元素A(a,b)加1,即A(a,b)=A(a,b)+1。所有的计算结束之后,在参数计算表决结果中找到A(a,b)的最大峰值,所对应的a0、b0就是原图像中共线点数目最多(共A(a,b)个共线点)的直线方程的参数;接下来可以继续寻找次峰值和第3峰值和第4峰值等等,它们对应于原图中共线点略少一些的直线。

注意:由于原图中的直线往往具有一定的宽度,实际上相当于多条参数极其接近的单像素宽直线,往往对应于参数空间中相邻的多个累加器。因此每找到一个当前最大的峰值点后,需要将该点及其附近点清零,以防算法检测出多条极其邻近的“假”直线。

对于上图的Hough变换空间情况如下图所示。
史上最详细的Hough直线检测_第2张图片
这种利用二维累加器的离散方法大大简化了Hough变换的计算,参数空间a−b上的细分程度决定了最终找到直线上点的共线精度。上述的二维累加数组A也被称为Hough矩阵。

2.极坐标参数空间

引入极坐标系的其中一个原因是如果有的直线的斜率不存在,那么直角坐标空间变化就不太合适。

极坐标中用如下参数方程表示一条直线。

ρ = x c o s θ + y s i n θ ( 4 ) ρ=xcosθ+ysinθ(4) ρ=xcosθ+ysinθ(4)
史上最详细的Hough直线检测_第3张图片
其中,ρ代表直线到原点的垂直距离,θ代表x轴到直线垂线的角度,取值范围为±90∘,如图所示。
史上最详细的Hough直线检测_第4张图片
与直角坐标类似,极坐标中的Hough变换也将图像坐标空间中的点变换到参数空间中。

更直观的,直角坐标系的三点共线,对应于 ρ − θ \rho-\theta ρθ 空间的多线共点。
史上最详细的Hough直线检测_第5张图片
上面这个图是如何得到的呢?为什么三点共线在极坐标系是曲线的交点?

我们把直角坐标和极坐标空间融合起来考虑。

在极坐标空间使用hough变换来检测直线的思想就是:为每一个点假设n个方向的直线,通常n=180,此时检测的直线的角度精度为1°,分别计算这n条直线的 ( ρ , θ (\rho,\theta (ρθ)坐标,得到n个坐标点。如果要判断的点共有N个,最终得到的 ( ρ , θ (\rho,\theta (ρθ)坐标有N * n个。有关这N * n个 ( ρ , θ (\rho,\theta (ρθ)坐标,其中theta是离散的角度,共有180个取值。

最重要的地方来了,如果多个点在一条直线上,那么必有这多个点在 θ = \theta= θ=某个值 θ i \theta_{i} θi时,这多个点的 ρ \rho ρ近似相等于 ρ i \rho_{i} ρi,也就是说这多个点都在极坐标直线 ( ρ i , θ i ) (\rho_i,\theta_i) ρi,θi上。

换句话说,在极坐标表示下,原图像坐标空间中共线的点变换到参数空间中后,在参数空间都相交于同一点,此时所得到的ρ、θ即为所求的直线的极坐标参数。与直角坐标不同的是,用极坐标表示时,图像坐标空间的共线的两点(xi,yi)和(xj,yj)映射到参数空间是两条正弦曲线或者参数空间的直线上,相交于点 ( ρ 0 , θ 0 ) (ρ_{0},θ_{0}) (ρ0,θ0)

下图就更直观了:

史上最详细的Hough直线检测_第6张图片
这个例子中,对于每个点均求过该点的6条直线的 ( ρ , θ ) (\rho,\theta) (ρθ)坐标,共求了3 * 6个 ( ρ , θ (\rho,\theta (ρθ)坐标。可以发现在 θ = 60 \theta=60 θ=60 时,三个点的 ρ \rho ρ都近似为80.7,由此可判定这三个点都在直线(80.7,60)上。

通过 ρ − θ \rho-\theta ρθ坐标系可以更直观表示这种关系,如下图:图中三个点的(r,theta)曲线汇集在一起,该交点就是同时经过这三个点的直线。
史上最详细的Hough直线检测_第7张图片
在实际的直线检测情况中,如果超过一定数目的点拥有相同的 ( ρ , θ ) (\rho,\theta) (ρθ)坐标,那么就可以判定此处有一条直线。在 ρ − θ \rho-\theta ρθ坐标系图中,明显的交汇点就标示一条检测出的直线。

如下图,可以判定出平面上的点共构成了两条直线,即检测出两条直线。
史上最详细的Hough直线检测_第8张图片

因此,我们可以通过检测 ρ − θ \rho-\theta ρθ 空间的交集点,来检测原始空间的线段。

接下来,就是要考虑 将 ρ , θ \rho,\theta ρ,θ离散化,形成离散化的Hough空间,类似于一个矩阵/图像(如下图),用于统计交集点的个数。
史上最详细的Hough直线检测_第9张图片

具体计算时,与直角坐标类似,也要在参数空间中建立一个二维数组累加器A,只是取值范围不同。对于一副大小为D×D的图像,通常ρ的取值范围为 [ − 2 D / 2 , 2 D / 2 ] , θ [−2\sqrt{D}/2,2\sqrt{D}/2],θ [2D /2,2D /2],θ的取值范围为[−90∘,90∘]。计算方法与直角坐标系中累加器的计算方法相同,最后得到最大的A所对应的(ρ,θ)。

3.Hough变换直线检测的Matlab实现

通过Hough在二值图像中检测直线需要以下3个步骤。
·>(1)利用hough()函数执行霍夫变换,得到霍夫矩阵。
·>(2)利用houghpeaks()函数在霍夫矩阵中寻找峰值点。
·>(3)利用houghlines()函数在之前2步结果的基础上得到原二值图像中的直线信息。

3.1 霍夫变换–Hough

调用形式:
[H,theta,rho]=hough(BW,param1,value1,param2,value2)

参数说明:
·BW是边缘检测后的二值图像;
·可选参数对param1,value1和param2,value2的合法取值如下:

param取值 含义
ThetaResolution Hough矩阵中θ轴方向上单位区间的长度(以“度”为单位),可取(0,90)区间上的实数,默认为1
RhoResolution Hough矩阵中 ρ \rho ρ轴方向上单位区间的长度,可取(0,norm(size(BW)))区间上的实数,默认为1

返回值:
·H是变换得到的霍夫矩阵
·θ, ρ \rho ρ分别对应于Hough矩阵每一列和每一行的θ, ρ \rho ρ值组成的向量。

补充:[m,n] = size(X)

补充:norm的用法,matlab  help norm 
NORM   Matrix or vector norm.
For matrices...
对于矩阵...
NORM(X) is the largest singular value of X, max(svd(X)).
NORM(X)是X的最大奇异值
NORM(X,2) is the same as NORM(X).
NORM(X,1) is the 1-norm of X, the largest column sum,
          = max(sum(abs(X))).
NORM(X,inf) is the infinity norm of X, the largest row sum,
          = max(sum(abs(X'))).
NORM(X,'fro') is the Frobenius norm, sqrt(sum(diag(X'*X))).
NORM(X,P) is available for matrix X only if P is 1, 2, inf or 'fro'.

For vectors...
对于向量...
NORM(V,P) = sum(abs(V).^P)^(1/P).
返回向量A的p范数
NORM(V) = norm(V,2).
返回向量A的2范数,即欧几里德范数。二范数等价于平方和开平方,Sqrt(X1^2+X2^2+...+Xn^2) 

3.2 寻找峰值–houghpeaks

调用形式:
peaks=houghpeaks(H,numpeaks,param1,value1,param2,value2)

参数说明:
·H是hough()函数得到的霍夫矩阵
·numpeaks是要寻找的峰值数目,默认为1
·可选参数对param1,value1和param2,value2的合法取值如下:

param取值 含义
Threshold 峰值的阈值,只有大于该阈值的点才被认为是可能的阈值,取值>0,默认为0.5×max(H())
NHoodSize 在每次检测出一个峰值后,NhoodSize指出了在该峰值周围需要清零的领域信息。以[m,n]的形式给出,其中m、n均为正的奇数。默认为大于等于size(H)/50的最小奇数。

返回值:
·peaks是一个Q×2的矩阵,每行的两个元素分别是某一峰值点再hough矩阵中的行、列索引,Q为找到的峰值点的数目。

3.3 提取直线段–houghlines

调用形式:
lines=houghlines(BW,theta,rho,peaks,param1,value1,param2,value2)

参数说明:
·BW是边缘检测后的二值图像
·theta,rho分别对应于Hough矩阵每一列和每一行的θ和ρθ和ρ值组成的向量。有hough()函数返回。
·peaks是一个包含峰值点信息的Q×2Q×2的矩阵,由houghpeaks()函数返回。
·可选参数对param1,value1和param2,value2的合法取值如下:

param取值 含义
FillGap 线段合并的阈值:如果对应于Hough矩阵某一个单元格(相同的θ和ρ)的两条线段之间的距离小于 FillGap,则合并为一个直线段。默认值为20.
MinLength 检测的直线段的最小长度阈值:如果检测出的直线段长度大于MinLength,则保留;丢弃小于MinLength的直线段。默认值为40.

返回值:
·lines是一个结构体数组,数组长度是找到的直线条数,而每一个数组元素(直线段结构体)的内部结构如下:

含义
point1 直线段的端点1
point2 直线段的端点2
thea 对应在霍夫矩阵中的θ
rho 对应在霍夫矩阵中的ρ

整体的代码实现

    I  = imread('circuit.tif');
    rotI = imrotate(I,33,'crop');
    BW = edge(rotI,'canny');
    [H,T,R] = hough(BW);
    imshow(H,[],'XData',T,'YData',R,'InitialMagnification','fit');
    xlabel('\theta'), ylabel('\rho');
    axis on, axis normal, hold on;
    P  = houghpeaks(H,5,'threshold',ceil(0.3*max(H(:))));
    x = T(P(:,2)); 
    y = R(P(:,1));
    plot(x,y,'s','color','white');

    % Find lines and plot them
    lines = houghlines(BW,T,R,P,'FillGap',5,'MinLength',7);
    figure, imshow(rotI), hold on
    max_len = 0;
    for k = 1:length(lines)
        xy = [lines(k).point1; lines(k).point2];
        plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');

        % plot beginnings and ends of lines
        plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');
        plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');

        % determine the endpoints of the longest line segment 
        len = norm(lines(k).point1 - lines(k).point2);
        if ( len > max_len)
          max_len = len;
          xy_long = xy;
        end
    end

    % highlight the longest line segment
    plot(xy_long(:,1),xy_long(:,2),'LineWidth',2,'Color','cyan');

前50个极值点:
史上最详细的Hough直线检测_第10张图片
这里的Hough空间域就像上面的图,如果随便给我一张图片,我要检测出所有的车道线,那么就是在找Hough参数空间中那个二维累加器中找到峰值,也就是极值,那些极值就是可以被检测原图片的直线,那么将参数空间反映射回图像空间,就能知道哪些地方是直线了,虚线和直线的区别就在于一个阈值,这些参数空间的极值点到底我们选不选,有些极值点是长线段实线,有些极值点可能就是短线段,就是车道虚线,那么我们怎么通过Hough空间的图像判断实线与虚线呢?

参考:https://blog.csdn.net/s12244315/article/details/52691544
https://blog.csdn.net/ws_20100/article/details/51159434
https://blog.csdn.net/sudohello/article/details/51335237

你可能感兴趣的:(计算机视觉/图像处理,课题相关)