本文简单介绍Hough原理,重点整理matlab的Hough工具箱——Hough/houghpeaks/houghlines函数
1、Hough检测直线原理
Hough变换目的
原始图像中直线的检测问题转化为寻找参数空间中的交点个数统计的极值问题。
基本原理
在r-theta参数空间中具有同样(theta,r)的点在一条直线上。
直角坐标系中无法表达垂直直线,极坐标系中,每一条直线都有一条过笛卡尔坐标系坐标原点的垂线,且对于每条直线来说,这条垂线是唯一的,而这条垂线,我们就用(theta, r)来表示,其中theta为该垂线与x轴所成的夹角,r 为该垂线的长度(原点到直线的距离)。所以可以用(theta,r)唯一表示一条直线。
也就是说图像空间中的一条线,在r-theta参数空间中为一个点,经过某一点的所有直线为r-theta参数空间中的一条曲线(三角函数曲线),r-theta参数空间中曲线的交点为图像中一条直线,r-theta参数空间中的一条水平直线为图像空间中的一个圆
具体检测方法
对于图像的每个像素点(x,y),对应到参数空间中,找到曲线的交点,交于此点的曲线个数就是图像空间的直线上的像素点数。
设置一个阈值,交于一点曲线个数超过这个值,图像中才算一条直线。
2、matlab工具箱
首先对图像进行边缘提取,然后对边缘进行Hough变换提取直线。
hough
对二值边缘图像进行Hough变换
[H,theta,rho] = hough(BW,Name,Value,...)
输入:
BW:边缘提取后的二值图的图像矩阵
可设置参数:‘RhoResolution’和’Theta’
RhoResolution:垂线长度的变化步长(对于数字图像,垂线的原点为左上角)
缺省值:1,取值范围:0~norm(size(BW))
Theta:过每一像素点的直线的旋转角度范围和步长
缺省值:-90:1:89
输出:
H:hough变换矩阵,(一行表示一垂线长度,一列表示一旋转角度)矩阵中的值表示过(theta, rho)的曲线的个数,即直线上像素点个数
theta:角度
rho:垂线长度
houghpeaks
提取后变换后的极值点
peaks = houghpeaks(H,numpeaks,Name,Value,...)
输入:
H:hough 变换矩阵
numpeaks:极值点个数
缺省值:1
可设置参数:‘Threshold’和’NHoodSize’
threshold:可以提取的最小极值
缺省值:最大极值的一半0.5*(max(H(:)))
NhoodSize:抑制区域的大小,即该区域内只取一个极值点(该参数的值为奇数数组)
缺省值:size(H)/50,或者>size(H)/50的奇数
输出:
peaks:参数空间中的极值点的坐标
houghlines
lines = houghlines(BW,theta,rho,peaks,Name,Value,...)
输入:
BW:边缘图
theta:与上面的hough算出来的theta一致
rho:与上面的hough算出来的一致
peaks:与上面的houghpeaks算出来的一致
可设置参数:‘FillGap’和’MinLength’
FillGap:具有相同的垂线长度(rho相同)的两根直线之间首尾距离小于FillGap的,可以认为是同一条直线
缺省值:20
MinLength:直线长度<MinLength 的舍去
缺省值:40
输出:
lines:为structure变量,包含直线的起点、终点、角度垂线、长度。
3、完整hough变换检测直线程序
close all; clear ;clc
I = imread('scratch.tif');
figure;
subplot(1,3,1);
imshow(I,[]);
BW = edge(I,'canny');%Canny方法提取图像边界,返回二值图像(边界1,否则0)
[H,T,R] = hough(BW,'RhoResolution',0.5,'Theta',-10:0.5:10);%计算二值图像的标准霍夫变换,H为霍夫变换矩阵,I,R为计算霍夫变换的角度和半径值
subplot(1,3,2);
imshow(H,[],'XData',T,'YData',R,'InitialMagnification','fit');%hough变换的图像
xlabel('\theta'), ylabel('\rho');
axis on,axis square,hold on;
P = houghpeaks(H,3,'threshold',0.7*max(H(:)));%提取3个极值点
x = T(P(:,2));
y = R(P(:,1));
plot(x,y,'s','color','white');%标出极值点
lines=houghlines(BW,T,R,P);%提取线段
subplot(1,3,3);
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