霍夫变换(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)^20.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
如有问题请留言。