图像特征检测——利用霍夫变换检测圆

霍夫变换是一种特征检测,它的算法流程大致如下,给定一个物件、要辨别的形状的种类,算法会在参数空间中执行投票来决定物体的形状,而这是由累加空间里的局部最大值来决定。
对于用霍夫变换检测直线而言,在二维笛卡尔坐标系中,直线上的一点映射到霍夫空间的一条直线:
在这里插入图片描述
然而直线上的两个不相同的点映射到霍夫空间的两条相交直线:
在这里插入图片描述
对于唯一确定的一条直线而言,它映射到霍夫空间是一个确定的点(k,q):
在这里插入图片描述
下面简单推导一下直线的极坐标方程(由于图像空间的像素点均是离散的,所以必须转化为直线的极坐标方程)。
在这里插入图片描述
上图中,点(p,q)是过原点的垂线与直线的交点,点(x,y)是直线上的任意一点,r是直线距离原点的距离即极径,通过上图点之间的位置关系,可以推导出下述公式:
在这里插入图片描述
在这里插入图片描述
k是直线的斜率,通过直线的点斜式方程
在这里插入图片描述
再将前三个等式带入,我们可以得到直线的极坐标方程
在这里插入图片描述
上述极坐标方程其实是一条正弦曲线。我们不妨任意选取x和y的值,假设x=2,y=3,得到如下图象:
在这里插入图片描述
在这里插入图片描述
上图是通过matlab对直线进行检测,通过霍夫变换得到的正弦曲线相交的情况,对交点次数大于设定阈值的点进行了标记。
matlab霍夫变换检测直线的运行结果如下所示:
在这里插入图片描述
所以同理可得,在笛卡尔坐标系中若若干个点均共线,则这些点映射到霍夫空间是多条正弦曲线相交于一点。显然,在霍夫空间中,曲线的交点相交次数越多,代表的参数越确定,即在极坐标系中正弦曲线相交次数最多的点就是我们在y-x笛卡尔坐标系中所要求得的直线方程。下面我们再看一下利用霍夫变换检测圆的原理。
由圆的一般方程公式
在这里插入图片描述
可知,由于圆在笛卡尔坐标系中是二维的所以映射到霍夫空间是三维的(即在霍夫空间中a,b,r是变量)。通过圆在笛卡尔坐标系中的参数方程
在这里插入图片描述
可知,在霍夫空间中有如下式子成立:
在这里插入图片描述
我们不妨通过固定圆的一般方程中的x和y来看一下当a,b,r作为变量时,在三维立体空间是什么样的曲面。
在这里插入图片描述
通过matlab得到上述三维空间的曲面和等值线图,为此我们知道对于笛卡尔坐标系中圆上的某个已知点映射到三维霍夫空间实际上是一个圆锥面。对于霍夫变换检测直线,若干个共线点映射到霍夫空间是若干条相交的直线。那么对于霍夫变换检测圆,若干个共圆的点映射到三维霍夫空间是若干个相交的圆锥面。同理,相交次数最多的点就是我们所要求得的在笛卡尔坐标系中的圆的圆心(a,b)和半径r。
在matlab程序中,先读取灰度图像,然后利用edge()函数选择’Sobel’算子进行边缘检测,返回二值化图像BW,在函数检测到的边缘地方为1其余地方为0。
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
以下是matlab程序源代码:

I=imread('图像名.xxx')
BW=edge(I,'sobel')
imshow(I)
hold on
param=findcircle(BW,15,35,1,0.01,0.5); 
for i=1:size(param,1)
    x0=param(i,1);y0=param(i,2);r0=param(i,3)
    xi=[-r0:0 0:r0]
    yi=round((r0^2-xi.^2).^0.5)
    plot(yi+y0,xi+x0,'color','g','linewidth',5)
    plot(-yi+y0,xi+x0,'color','g','linewidth',5)
end
title('经过霍夫变换得到的特征提取','fontsize',20)
function[circlefind]=findcircle(img,minr,maxr,stepr,stepa,percent)
r=round((maxr-minr)/stepr)+1;%可增长的步长个数
angle=round(2*pi/stepa);
[m,n]=size(img);
houghspace=zeros(m,n,r);%霍夫空间
[m1,n1]=find(img);%返回二值化边缘检测图像Img中非零点的坐标,m1存放横坐标,n1存放纵坐标
num=size(m1,1);%非零点个数
%a = x-r*cos(angle), b = y-r*sin(angle)
for i=1:num
    for j=1:r
        for k=1:angle
            a=round(m1(i)-(minr+(j-1)*stepr)*cos(k*stepa));
            b=round(n1(i)-(minr+(j-1)*stepr)*sin(k*stepa));
            if(a>0&&a<=m&&b>0&&b<=n)
                houghspace(a,b,j)=houghspace(a,b,j)+1;
            end
        end
    end
end
par=max(max(max(houghspace)));%找出个数最多的圆的数量作为阈值
par2=par*percent;%百分比percent阈值调整
[m2,n2,r2]=size(houghspace);
circlefind=[];%存储大于阈值的圆的圆心坐标及半径
for i=1:m2
    for j=1:n2
        for k=1:r2
            if (houghspace(i,j,k)>=par2)
                a=[i,j,minr+k*stepr];
                circlefind=[circlefind;a];
            end
        end
    end
end
end

结果如下所示:
在这里插入图片描述
findcircle()函数中,参数minr,maxr分别是圆的最小和最大半径,在参数值选择上要注意合理选择,如果minr的值设置的过大,则很有可能很多半径较小的圆无法检测出来;如果maxr设置的过小,则半径较大的圆可能无法检测出来。所以在参数设置之前要对圆的半径取值范围有大概了解。而参数stepr可以理解为半径r的增长步长,如果stepr选择过小,则程序迭代次数过多,计算量大,对于图像中圆的半径值变化不太细微的情况应适当让stepr的值高一些。而percent是阈值参数,设置的时候不要太高,否则会造成漏选的情况。stepa参数的取值应尽可能的接近0,程序中参数方程中的角度是k*stepa,其取值范围为(0,2π]。

发布了81 篇原创文章 · 获赞 22 · 访问量 7702

猜你喜欢

转载自blog.csdn.net/qq_38883271/article/details/103519556