hyb965149985

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

霍夫变换

霍夫变换是1972年提出来的,最开始就是用来在图像中过检测直线,后来扩展能检测圆、曲线等。

直线的霍夫变换就是 把xy空间的直线 换成成 另一空间的点。就是直线和点的互换。

 

我们在初中数学中了解到,一条直线可以用如下的方程来表示:y=kx+bk是直线的斜率,b是截距。

我们转换下变成:b=-kx+y。我们是不是也可以把(kb)看作另外一个空间中的点?这就是k-b参数空间。 这样,我们就把一条x-y直线用一个(k,b)的点表示出来了。

我们看到,在x-y图像空间中的一个点,变成了k-b参数空间中的一条直线,而x-y图像空间中的2点连成的直线,变成了k-b参数空间中的一个交点。

如果x-y图像空间中有很多点在k-b空间中相交于一点,那么这个交点就是我们要检测的直线。这就是霍夫变换检测直线的基本原理。

当然,有一个问题需要注意,图像空间中如果一条直线是垂直的,那么斜率k是没有定义的(或者说无穷大)。为了避免这个问题,霍夫变换采用了另一个参数空间:距离-角度参数空间。也就是极坐标。

我们在中学中学过,平面上的一个点也可以用距离-角度来定义,也就是极坐标。那么在图像中,每一个点都可以用距离和角度来表达:

 

但是,使用距离-角度后,点(xy)与距离,角度的关系变成了:

ρ=xcosθ+ysinθ

于是,在新的距离-角度参数空间中,图像中的一个点变成了一个正弦曲线,而不是k-b参数空间中的直线了。这些正弦曲线的交点就是图像空间中我们要检测的直线了。

 

Matlab霍夫变换的函数详解

[H, theta, rho] = hough(BW,ParameterName, ParameterValue)

BW:二值图

ParameterName'RhoResolution''Theta'

RhoResolution-指定在累计数组中(检测极值)的检测间隔?默认为1

Theta-指定检测的角度范围(不超过-90~90度)以及间隔,例如-90:0.5:89.5,默认-90:1:89

H:累计数组

ThetaH对应的θ,实际上H的大小就是Rho×Theta

RhoH对应的ρ

 这两个参数值的注意,RhoResolution太大覆盖不到极值点,检测到一些不对应直线的次极值,

 

峰值提取

peaks = houghpeaks(H,numpeaks)

peaks = houghpeaks(...,param1, val1, param2, val2)

H:累计数组;

Numpeaks:指定需要检测的峰值个数;

Param1:可以是'Threshold''NHoodSize'

'Threshold'-指定峰值的域值,默认是0.5*max(H(:))

'NHoodSize'-是个二维向量[m,n],检测到一个峰值后,将峰值周围[m,n]内元素置零。

 

画直线段

lines = houghlines(BW,theta, rho, peaks)

lines = houghlines(...,param1, val1, param2, val2)

 

BW:二值图

Thetarhopeaks:分别来自函数houghhoughpeaks

Lines:结构数组,大小等于检测到的直线段数,每个单元包含

Point1point2:线段的端点

Thetarho:线段的thetarho

 

下面实例演示

用霍夫变换判断矩形

所用图形是我用画图工具制作的,图片很干净,所以不需要滤波等措施。以下是图案。

img  = imread('a.png');
img_gray = rgb2gray(img);

%背景是黑的!!!
threshold =graythresh(img_gray);%取阈值
bw=im2bw(img_gray,threshold);
if length(bw(bw==1))>length(bw(bw==0))
    bw=~bw;
end
%填充
bw = imfill(bw,'holes');

figure(), imshow(img_gray), title('image');



[B,L] = bwboundaries(bw,'noholes');
stats = regionprops(L,'Area','Centroid','image');
boundary = B{1};
delta_sq = diff(boundary).^2;
perimeter = sum(sqrt(sum(delta_sq,2)));
% obtain the area calculation corresponding 
area = stats(1).Area;
% compute the roundness metric
metric = 4*pi*area/perimeter^2;
if metric>0.9
    disp('yuan')
else
    
    % the canny edge of image
    BW = edge(bw,'canny');
    % Iedge=edge(Ihsv,'sobel');    %边沿检测
    %BW = imdilate(BW,ones(3));%图像膨胀
    figure(), imshow(BW), title('image edge');
    % the theta and rho of transformed space
    [H,Theta,Rho] = hough(BW,'RhoResolution',1.2);
    figure(), imshow(H,[],'XData',Theta,'YData',Rho,'InitialMagnification','fit'),...
        title('rho\_theta space and peaks');
    xlabel('\theta'), ylabel('\rho');
    axis on, axis normal, hold on;
    % label the top 5 intersections
    P  = houghpeaks(H,4,'threshold',ceil(0.1*max(H(:))),'NHoodSize',[35,11]);
    x = Theta(P(:,2)); 
    y = Rho(P(:,1));
    plot(x,y,'*','color','r');


    % find lines and plot them
    lines = houghlines(BW,Theta,Rho,P);
    figure(), imshow(img),title('final image');
    hold on
    b_len = ones(1,length(lines));
    for k = 1:length(lines)
     xy = [lines(k).point1; lines(k).point2];
     b_len(1,k)=sqrt((xy(1,1)-xy(2,1))^2+(xy(1,2)-xy(2,2))^2);
     plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','r');
     hold on
    end
    if var(b_len)<10
        disp('正方形')
    else
        disp('长方形')
    end
end

 然后得到结果

变换参数域图像(很完美,4个点)

结果图像

基本包含在原图形上,测试成功!

 

参考文献:

[1] http://blog.sina.com.cn/s/blog_ac7218750101giyf.html

 

[2] https://blog.csdn.net/saltriver/article/details/80547245

 

[3] https://ww2.mathworks.cn/help/images/ref/hough.html

 

盘外篇

自己写个Hough变换? hough的原理很简单,可以自己尝试以下。

那么我们检测一下 直线的斜率。

下面上代码

clear all;

img  = imread('demo1.png');
img_gray = rgb2gray(img);

%二值化
threshold =graythresh(img_gray);%取阈值
bw=im2bw(img_gray,threshold);
if length(bw(bw==1))>length(bw(bw==0))
    bw=~bw;
end

figure(), imshow(bw), title('image');
% %填充
% bw = imfill(bw,'holes');
% %边沿检测
%the canny edge of image
%bw = edge(bw,'canny');

bw = imdilate(bw,ones(8)); %图像膨胀(因为直线太细会使误差增大)
%figure(), imshow(bw), title('image ');
%the theta and rho of transformed space
[H,Theta,Rho] = hough1(bw);
figure(), imshow(H,[],'XData',Theta,'YData',Rho,'InitialMagnification','fit'),...
    title('rho\_theta space and peaks');
xlabel('\theta'), ylabel('\rho');
axis on, axis normal, hold on;
%label the top 1 intersections
%P = houghpeaks(H,1);
[xx,yy]=find(H==max(max(H)),1);
P=[xx,yy];
x = Theta(P(:,2));
y = Rho(P(:,1));
plot(x,y,'*','color','r');

[m,n]=size(bw);
label=zeros(m,n);
xy=[];
for ii=1:length(bw)
    jj=ceil((y-ii*cos(x/180*pi))/sin(x/180*pi));
    if jj>=1&& jj<=n
        label(ii,jj)=1;
        if bw(ii,jj)==1
            xy=[xy;jj,ii];  %因为plot和imshow的xy轴是镜像关系!
        end            
    end
end
    
    
%find lines and plot them
%lines = houghlines(bw,Theta,Rho,P);
figure(), imshow(img),title('final image');
hold on
plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','r');

k=-sin(x/180*pi)/cos(x/180*pi);
b=y/cos(x/180*pi);
disp(['斜率是',num2str(k)])
disp(['y轴截距是',num2str(b)])

%ezplot('x*cos(-72/180*pi)+y*sin(-72/180*pi)=-31',[0,256])

  下面就是自己写的hough变换函数了

function [h, theta, rho] = hough1(f, dtheta, drho)

if  nargin < 3
   drho = 1;
end
if  nargin < 2
   dtheta = 1;
end
 
f = double(f);
[M,N] = size(f);
theta = linspace(-90, 0, ceil(90/dtheta) + 1);
theta = [theta -fliplr(theta(2:end - 1))];
ntheta = length(theta);
 
D = sqrt((M - 1)^2 + (N - 1)^2);
q = ceil(D/drho);
nrho = 2*q - 1;
rho = linspace(-q*drho, q*drho, nrho);
 
[x, y, val] = find(f);
x = x - 1;  y = y - 1;
 
h = zeros(nrho, length(theta));
 
for  k = 1:ceil(length(val)/1000)
   first = (k - 1)*1000 + 1;
   last  = min(first+999, length(x));
   
   x_matrix     = repmat(x(first:last), 1, ntheta);
   y_matrix     = repmat(y(first:last), 1, ntheta);
   val_matrix   = repmat(val(first:last), 1, ntheta);
   theta_matrix = repmat(theta, size(x_matrix, 1), 1)*pi/180;
   
   rho_matrix = x_matrix.*cos(theta_matrix) + ...
       y_matrix.*sin(theta_matrix);
   slope = (nrho - 1)/(rho(end) - rho(1));
   rho_bin_index = round(slope*(rho_matrix - rho(1)) + 1);
   
   theta_bin_index = repmat(1:ntheta, size(x_matrix, 1), 1);
   
   h = h + full(sparse(rho_bin_index(:), theta_bin_index(:), ...
                       val_matrix(:), nrho, ntheta));
end

  结果还不错

 

posted on 2018-12-16 13:59  hyb965149985  阅读(8054)  评论(0编辑  收藏  举报