霍夫变换(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. 效果图:

python霍夫变换检测圆形优化 matlab霍夫变换找圆心_python霍夫变换检测圆形优化

python霍夫变换检测圆形优化 matlab霍夫变换找圆心_Matlab_02

python霍夫变换检测圆形优化 matlab霍夫变换找圆心_python霍夫变换检测圆形优化_03

python霍夫变换检测圆形优化 matlab霍夫变换找圆心_ci_04

如有问题请留言。