欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Hough 圆变换----Matlab实现

程序员文章站 2022-05-22 15:51:45
...

 

霍夫变换(Hough)是一个非常重要的检测间断点边界形状的方法。它通过将图像坐标空间变换到参数空间,来实现直线与曲线的拟合。

参数空间可以表示为(a,b,r),图像坐标空间中的一个圆对应参数空间中的一个点。

                                           A(a,b,r)。

计算过程是让a,b在取值范围内增加,解出满足上式的r值,每计算出一个(a,b,r)值,就对相应的数组元素A(a,b,r)加1。计算结束后,找到的超过阈值的A(a,b,r)所对应的a,b,r就是所求的圆的参数。

 

函数程序:

 

 

function [Hough_space,Hough_circle_result,Para] = Hough_circle(BW,Step_r,Step_angle,r_min,r_max,p)  
%---------------------------------------------------------------------------------------------------------------------------  
% input:  
% BW:二值图像;  
% Step_r:检测的圆半径步长;  
% Step_angle:角度步长,单位为弧度;  
% r_min:最小圆半径;  
% r_max:最大圆半径;  
% p:以p*Hough_space的最大值为阈值,p取0,1之间的数.  
% a = x-r*cos(angle); b = y-r*sin(angle);  
%---------------------------------------------------------------------------------------------------------------------------  
% output:  
% Hough_space:参数空间,h(a,b,r)表示圆心在(a,b)半径为r的圆上的点数;  
% Hough_circle:二值图像,检测到的圆;  
% Para:检测到的圆的圆心、半径.  
%---------------------------------------------------------------------------------------------------------------------------  
circleParaXYR=[];  
Para=[];  
%得到二值图像大小  
[m,n] = size(BW);  
%计算检测半径和角度的步数、循环次数 并取整,四舍五入  
size_r = round((r_max-r_min)/Step_r)+1;  
size_angle = round(2*pi/Step_angle);  
%建立参数空间  
Hough_space = zeros(m,n,size_r);  
%查找非零元素的行列坐标  
[rows,cols] = find(BW);  
%非零坐标的个数  
ecount = size(rows);  
% Hough变换  
% 将图像空间(x,y)对应到参数空间(a,b,r)  
% a = x-r*cos(angle)  
% b = y-r*sin(angle)  
for i=1:ecount  
    for r=1:size_r %半径步长数按一定弧度把圆几等分  
        for k=1:size_angle  
            a = round(rows(i)-(r_min+(r-1)*Step_r)*cos(k*Step_angle));  
            b = round(cols(i)-(r_min+(r-1)*Step_r)*sin(k*Step_angle));  
            if (a>0&&a<=m&&b>0&&b<=n)  
                Hough_space(a,b,r)=Hough_space(a,b,r)+1;%h(a,b,r)的坐标,圆心和半径  
            end  
        end  
    end  
end  
% 搜索超过阈值的聚集点,对于多个圆的检测,阈值要设的小一点!通过调此值,可以求出所有圆的圆心和半径返回值就是这个矩阵的最大值  
max_para = max(max(max(Hough_space)));  
%一个矩阵中,想找到其中大于max_para*p数的位置  
index = find(Hough_space>=max_para*p);  
length = size(index);%符合阈值的个数  
Hough_circle_result=zeros(m,n);  
%通过位置求半径和圆心。  
for i=1:ecount  
    for k=1:length  
        par3 = floor(index(k)/(m*n))+1;  
        par2 = floor((index(k)-(par3-1)*(m*n))/m)+1;  
        par1 = index(k)-(par3-1)*(m*n)-(par2-1)*m;  
        if((rows(i)-par1)^2+(cols(i)-par2)^2<(r_min+(par3-1)*Step_r)^2+5&&...  
          (rows(i)-par1)^2+(cols(i)-par2)^2>(r_min+(par3-1)*Step_r)^2-5)  
            Hough_circle_result(rows(i),cols(i)) = 1;%检测的圆  
        end  
    end  
end  
% 从超过峰值阈值中得到    
for k=1:length    
    par3 = floor(index(k)/(m*n))+1;%取整    
    par2 = floor((index(k)-(par3-1)*(m*n))/m)+1;    
    par1 = index(k)-(par3-1)*(m*n)-(par2-1)*m;    
    circleParaXYR = [circleParaXYR;par1,par2,par3];    
    Hough_circle_result(par1,par2)= 1; %这时得到好多圆心和半径,不同的圆的圆心处聚集好多点,这是因为所给的圆不是标准的圆    
end   
%集中在各个圆的圆心处的点取平均,得到针对每个圆的精确圆心和半径;  
while size(circleParaXYR,1) >= 1  
    num=1;  
    XYR=[];  
    temp1=circleParaXYR(1,1);  
    temp2=circleParaXYR(1,2);  
    temp3=circleParaXYR(1,3);  
    c1=temp1;  
    c2=temp2;  
    c3=temp3;  
    temp3= r_min+(temp3-1)*Step_r;  
    if size(circleParaXYR,1)>1  
        for k=2:size(circleParaXYR,1)  
            if (circleParaXYR(k,1)-temp1)^2+(circleParaXYR(k,2)-temp2)^2 > temp3^2  
                XYR=[XYR;circleParaXYR(k,1),circleParaXYR(k,2),circleParaXYR(k,3)];  %保存剩下圆的圆心和半径位置  
            else  
                c1=c1+circleParaXYR(k,1);  
                c2=c2+circleParaXYR(k,2);  
                c3=c3+circleParaXYR(k,3);  
                num=num+1;  
            end  
        end  
    end  
    c1=round(c1/num);  
    c2=round(c2/num);  
    c3=round(c3/num);  
    c3=r_min+(c3-1)*Step_r;  
    Para=[Para;c1,c2,c3]; %保存各个圆的圆心和半径的值  
    circleParaXYR=XYR;  
end  

 

主程序:

clc  
clear all  
%------------------------------------------------------------------------------  
%模拟图像  
I=ones(256,256);  
I(20:20:220,20:20:220)=0;  
for i=20:20:220  
    for j=20:20:220  
        circle_size=floor(rand*4);  
        for ci=i-circle_size:i+circle_size  
            for cj=j-circle_size:j+circle_size  
                if (ci-i)^2+(cj-j)^2<circle_size^2  
                    I(ci,cj)=0;  
                end  
            end  
        end  
    end  
end  
I= imgaussfilt(I, 4);  
I(I>0.9)=1;  
I(I<0.9)=0;  
%---------------------------------------------------------------------------------  
%加入直线干扰  
I(64,:)=0;I(:,64)=0;I(128,:)=0;I(:,128)=0;I(192,:)=0;I(:,192)=0;  
figure(1);  
imshow(I,[]),title('原图');  
%---------------------------------------------------------------------------------  
% 用sobel进行边缘检测  
BW = edge(I,'sobel');  
%---------------------------------------------------------------------------------  
%设置参数:  
%检测的圆半径步长为1  
Step_r = 0.5;  
%角度步长0.1,单位为弧度  
Step_angle = 0.1;  
%最小圆半径2  
minr =5;  
%最大圆半径30  
maxr = 20;  
%以thresh*hough_space的最大值为阈值,thresh取0-1之间的数  
thresh = 0.8;  
circleParaXYR=[];  
%---------------------------------------------------------------------------------  
%开始检测  
[Hough_space,Hough_circle_result,Para] = Hough_circle(BW,Step_r,Step_angle,minr,maxr,thresh);  
circleParaXYR=Para;  
axis equal  
figure(2);  
imshow(BW,[]),title('边缘');  
axis equal  
figure(3);  
imshow(Hough_circle_result,[]),title('检测结果');  
axis equal  
figure(4),imshow(I,[]),title('检测出图中的圆')  
hold on;  
%---------------------------------------------------------------------------------  
%以红色线标记出的检测圆心与圆  
plot(circleParaXYR(:,2), circleParaXYR(:,1), 'r+');  
for k = 1 : size(circleParaXYR, 1)  
    t=0:0.01*pi:2*pi;  
    x=cos(t).*circleParaXYR(3,k)+circleParaXYR(2,k);  
    y=sin(t).*circleParaXYR(3,k)+circleParaXYR(1,k);  
    plot(x,y,'r-');  
end  

 

  1. 效果图:

Hough 圆变换----Matlab实现

Hough 圆变换----Matlab实现

Hough 圆变换----Matlab实现

Hough 圆变换----Matlab实现

如有问题请留言。