理想情况下,之前讨论的边缘检测方法应该只产生边缘上的像素。实际上,结果由于噪声、不均匀照明引起的边缘断裂和杂散的亮度不连续而难以得到完全的边缘特性。因此,典型的边缘检测算法遵循用链接过程把像素组装成有意义的边缘的方法。一种寻找并链接图像中线段的处理方式是Hough变换。
理论基础
图像是一个个离散的像素点构成的,如果在图像中有一条直线,那也是一系列的离散点构成的。
而我们知道一条直线可以用如下的方程来表示:
y=kx+b,
k是直线的斜率,b是截距。
我们再看上面的直线方程:y=kx+b,(x,y)就是x-y空间中的点。我们转换下变成:
b=-kx+y。
我们是不是也可以把(k,b)看作另外一个空间中的点?这就是k-b参数空间。
我们看到,在x-y图像空间中的一个点,变成了k-b参数空间中的一条直线,而x-y图像空间中的2点连成的直线,变成了k-b参数空间中的一个交点。
如果x-y图像空间中有很多点在k-b空间中所对应的线相交于一点,那么这个交点(k1,b1)就是我们要检测的直线。这就是霍夫变换检测直线的基本原理。
由于其存在与X轴垂直、即K无穷大无法取值的情况。故我们换做极坐标空间来替换k-b空间。
此时的直线表达式则为:
此时两个空间则如下图,此时x-y空间的一点则对应极坐标空间的一条正弦线。这些正弦曲线的交点就是图像空间中我们要检测的直线了。
Hough变换实战现场
基于上面的基本原理,小白也在MATLAB中写了一下相关的代码。我们这次还是检测上次那套房子的边缘线。
I = imread('Fig1006(a).tif');
figure;
subplot(1,4,1);
imshow(I);
BW = edge(I,'prewitt');%prewitt方法提取图像边界,返回二值图像(边界1,否则0)
subplot(1,4,2);
imshow(BW);
[H,T,R] = hough(BW);%计算二值图像的标准霍夫变换,H为霍夫变换矩阵,I,R为计算霍夫变换的角度和半径值
subplot(1,4,3);
imshow(H,[],'XData',T,'YData',R,'InitialMagnification','fit');%hough变换的图像
xlabel('\theta'), ylabel('\rho');
axis on,axis square,hold on;
P = houghpeaks(H,40);%提取40个极值点
x = T(P(:,2));
y = R(P(:,1));
plot(x,y,'s','color','white');%标出极值点
lines=houghlines(BW,T,R,P);%提取线段
subplot(1,4,4);
imshow(I), hold on;
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');%画出线段
plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');%起点
plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');%终点
end
运行代码,效果图如下:
可以看到再用edge函数的prewitt 方法检测到边缘后,我们可以看到其实其所检测的边缘是断断续续的,所以为了能让其“断线连接”,我们随后就引入了Hough变换的手段,这里小白设置的是从变换后的空间(第三个图)里提取40个极值点,对应过来就是检测出40条直线,并显示在第四个图中。这样就一目了然了!
小白在这里介绍了Hough变换最基本的直线检测,其实目前已经衍生到了对于曲线的检测,有兴趣的同学可以深入的了解一下哟!