标准直线Hough变换采用如下参数化直线方程:
x*cosθ+y*sinθ=ρ (1)
式中,θ表示直线的法线方向,0≤θ<180,ρ表示原点至直线的距离(本文中θ的单位均为“度”,ρ的单位均为“像素”)。通常在图像直线检测中不直接使用图像坐标系,而是使用原点在图像中心处、y轴方向与图像的y 方向相反的正交坐标系,如图1所示的Oxy坐标系。
为了进行直线检测,首先需要按一定的量化间隔将可能的θ与ρ 取值范围离散化为若干区间,其中θ的取值范围规定在[0,180)的区间内,而ρ的取值范围则由图像矩形的顶点至原点即图像中心的距离确定;整个可能的θ-ρ 参数空间被离散化为一个二维的网格,对每一个可能的离散化参数对(θi,ρj)即每个网格单元设置一个计数器。然后对图像中的每个特征点(x0,y0),遍历所有的离散θ值,根据式(1)计算出每个θi值下对应的ρ 值及相应的离散区间ρi,并对计数器(θi,ρi)的值加1,这一过程称为特征点对参数空间投票。当所有的特征点均完成了投票后,寻找出参数空间中计数器值大于某一给定阈值T 的局部极大点,这些局部极大点对应的直线参数对(θ,ρ)即代表了检测得到的图像中的直线。
以图1为例,对于每一个在直线l0上的点,均有
x*cosθ0 + y*sinθ0 = ρ0
可以设一个截距式参数方程,x/a + y/b = 1,求得cosθ0,sinθ0;对于点p,Xp,Yp满足Xp/a + Yp/b = 1,然后即可验证Xp*cosθ0+Yp*sinθ0=ρ0.
所以对于计数器 (θ0,ρ0)而言它极有可能为最大值。得到θ0和ρ0后直线也就检测出来了。
下面的代码将检测直线,并标记出来。
<span style="font-size:18px;">void CImageColorProcess::HoughLineDetect(LPBYTE binaryimage, LPBYTE lpDst, int nSrcCount, int nW, int nH, int threshold)
{//binaryimage是二值图像,threshold是检测阈值
int nSrcLine = LINEWIDTH(nW*nSrcCount);
int roMax = (int)sqrt(nW * nW + nH * nH) + 1;
int* mark = new int[roMax*180];
for (int i = 0; i < roMax; i++)
for (int j = 0; j < 180; j++)
mark[i * 180 + j] = 0;
double* theta = new double[180];
for (int i = 0; i < 180; i++)
{
theta[i] = (double)i * PI / 180.0;
}
double roValue = 0.0;
int transValue = 0;
for (int y = 0; y < nH; y++)
{
for (int x = 0; x < nW; x++)
{
if (binaryimage[x + y * nW ] == 0)
{
for (int k = 0; k < 180; k++)
{
roValue = (double)x * cos(theta[k]) + (double)y * sin(theta[k]);
transValue = (int)(roValue / 2 + roMax / 2);
mark[transValue*180+k]++;
}
}
}
}
for (int y = 0; y < nH; y++)
{
for (int x = 0; x < nW; x++)
{
lpDst[y*nSrcLine + 3 * x] = 255;
lpDst[y*nSrcLine + 3 * x+1] = 255;
lpDst[y*nSrcLine + 3 * x+2] = 255;
int T = x + y * nW ;
if (binaryimage[T] == 0)
{
for (int k = 0; k < 180; k++)
{
roValue = (double)x * cos(theta[k]) + (double)y *sin(theta[k]);
transValue = (int)(roValue / 2 + roMax / 2);
if (mark[transValue*180+ k] > threshold)
{
lpDst[y*nSrcLine+3*x] = (byte)0;//做标记
}
}
}
}
}
}</span>
下面是检测结果:
检测直线的霍夫变换提供了在图像中寻找直线的一种算法,是最简单的一种情形,后来发展到检测圆、椭圆、还有一般图形的霍夫变换,其核心思想是把图像中属于某种图形的点集(二维)映射到一个点(可以是高维)上,这个点记录了点集中点的数目,使得程序通过搜索峰值找到该点,这个点就是后面要说到的图形的参数,而该参数的范围就叫做参数空间。霍夫变换不仅能够识别出图像中有无需要检测的图形,而且能够定位到该图像的位置、角度等。