霍夫变换于1962年由PaulHough 首次提出,后于1972年由RichardDuda和PeterHart推广使用,经典霍夫变换用来检测图像中的直线,后来霍夫变换扩展到任意形状物体的识别,多为圆和椭圆。
一 基本思想
Hough的基本思想就是构造参数平面,找出参数平面上的峰值点,从而得到所需检测形状的参数。
以直线问题来阐述:在找出边界点集之后,需要连接,形成完整的边界图形描述,对于包含n个点的点集,找出共线的点集和直线方程。
构造ab参数平面:
则xy平面上的任意一条直线y=a*x+b,都对应于参数平面上的一个点,而在xy平面上过一个点的所有直线,构成参数ab平面上的一条直线。
如果点(x1,y1)与点(x2,y2)共线,那么这两点在参数ab平面上的直线将有一个交点。
在参数ab平面上相交直线最多的点,对应的xy平面上的直线就是我们的解。
极坐标表示:
由于垂直直线的斜率为无限大,实际应用常用极坐标来表示,原理和上述一样。
则上述描述变为:
(1)在图像空间(x,y)域中的一点对应于参数空间(ρ,θ)域中的一条正弦曲线
(2)参数空间中的一点对应于图像空间(x,y)中的一条直线。
(3)图像空间(x,y)域中的一条直线上的n个点,对应于参数空间中经过一个公共点的n条曲线
(4)变换空间中一条曲线上的n个点对应于空间(x,y)中过一公共点的n条直线。
二 编程方法
(1)建立一个2-D累加数组(可用一维数组表示),设这个累加数组为A(Theta, R)。
(2)开始时设置数组A为0,然后对每个图像空间中的给定边缘点,让Theta取遍Theta轴上所有的可能值,并根据R=x*cos(theta)+y*sin(theta)算出对应的R。
(3)再根据Theta和R的值(都已整数化),对A进行累加:A(Theta , R)++。累加结束后,根据(Theta , R)的值就可知道有多少点是共线的,即A(Theta , R)的值就是在(Theta , R)处共线点的个数,同时(Theta , R)值也给出了直线方程的参数。三 代码
bool HoughTrans(int* pPoints,int pointNum,int RMax,int &lineR,int &lineTheta)
{
//x*cos(theta)+y*sin(theta)=r;
int k,maxValue;
int *pAccumulateArr=NULL; //累加数组
int thetaMax=360;
int theta;
int rValue;
float fRate = (float)(PI/180);
int AccuArrLength=(thetaMax+1)*(RMax+1);
pAccumulateArr=(int*)malloc(AccuArrLength*sizeof(int));
memset(pAccumulateArr,0,AccuArrLength*sizeof(int));
for (k=0;k<pointNum;k++)
{
for (theta=0;theta<=thetaMax;theta++)
{
rValue=(float)(pPoints[k*2]) * cos(theta * fRate) + float(pPoints[k*2+1]) * sin(theta * fRate)+0.5;
if (rValue>=0)
{
int indexTemp=rValue*(thetaMax+1)+theta;
if (rValue<=RMax && indexTemp>=0)
{
pAccumulateArr[indexTemp]++;
}
}
}
}
//得到最佳参数
maxValue=0;
lineR=0;
lineTheta=0;
for (rValue=0;rValue<=RMax;rValue++)
{
for (theta=0;theta<=thetaMax;theta++)
{
int iCount = pAccumulateArr[rValue * (thetaMax+1) + theta];
if (maxValue<iCount)
{
maxValue=iCount;
lineR=rValue;
lineTheta=theta;
}
}
}
free(pAccumulateArr);
pAccumulateArr=0;
if (maxValue!=0)
{
return true;
}
else
{
return false;
}
}