Hough直线检测



霍夫变换就是通过图形的一种表示模式,加上一种转换方法,把图形的点集投射到一个点上以便检测。

标准直线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>

下面是检测结果:



检测直线的霍夫变换提供了在图像中寻找直线的一种算法,是最简单的一种情形,后来发展到检测圆、椭圆、还有一般图形的霍夫变换,其核心思想是把图像中属于某种图形的点集(二维)映射到一个点(可以是高维)上,这个点记录了点集中点的数目,使得程序通过搜索峰值找到该点,这个点就是后面要说到的图形的参数,而该参数的范围就叫做参数空间。霍夫变换不仅能够识别出图像中有无需要检测的图形,而且能够定位到该图像的位置、角度等。



版权声明:

原文地址:https://www.cnblogs.com/walccott/p/4957131.html