以一般化视角串联霍夫变换,从直线到圆再到广义霍夫变换

                          以一般化视角串联霍夫变换(hough transform),从直线到圆再到广义霍夫变换

                                                                                                                          http://blog.csdn.net/cy513/article/details/4269340


     计算机视觉中经常需要识别或者定位某些几何图形,比如直线、圆、椭圆,还有其他一些图形。检测直线的霍夫变换提供了在图像中寻找直线的一种算法,是最简单的一种情形,后来发展到检测圆、椭圆、还有一般图形的霍夫变换,其核心思想是把图像中属于某种图形的点集(二维)映射到一个点(可以是高维)上,这个点记录了点集中点的数目,使得程序通过搜索峰值找到该点,这个点就是后面要说到的图形的参数,而该参数的范围就叫做参数空间。霍夫变换不仅能够识别出图像中有无需要检测的图形,而且能够定位到该图像(包括位置、角度等),这就非常有用了。接下来将通过分析从简单到复杂的霍夫变换,导出霍夫变换的实质。


       直线:检测直线的霍夫变换使用含极坐标参数的直线表示型式简称极坐标式(不是极坐标方程,因为还是在笛卡尔坐标下表示)——  

其中的两个参数的意义如下图:

以一般化视角串联霍夫变换,从直线到圆再到广义霍夫变换_第1张图片

 

 

为什么要用极坐标式而不直接用一般形式:ax+by=c(归一化可以去掉参数c),或者其他的如斜截式、截距式呢?首先它们都会遇到奇异情况,比如c=0,斜率=无穷大,其中一个截距=0;再一个是某些形式的参数空间不是闭的,比如斜截式的斜率k,取值范围从0到无穷大,给量化搜索带来了困难。而极坐标式就妙在距离和角度两个参数都是有界的,而且正余弦函数也有界不会发生奇异情况。

       直线霍夫变换有两个参数,且这两个参数通过极坐标式相关联,所以程序在投票阶段(图形点集转换到一个点)只需要遍历其中一个,搜索峰值在二维参数空间进行。

 

       圆:霍夫变换检测圆使用圆的标准式就可以了——

我们发现圆的方程又比直线多了一个参数,这三个参数通过上面的方程相关联,因此在投票阶段需要遍历其中两个,搜索峰值在三维参数空间进行。如果图像比较大,那么这样的遍历搜索是相当耗时的,所以为了满足实时性后来又发展出其他检测圆的霍夫变换,比如概率霍夫变换,结合梯度信息的霍夫变换。

      

       霍夫变换检测椭圆如果使用椭圆的标准式,那么将会有五个参数,它们通过标准式相关,检测圆就已经相当耗时了,如果再用这中方程形式处理势必失去实际用途。

 

       Ballard (1981) 一般化了霍夫变换(Hough,1962),利用图形梯度量加快算法速度,形成了广义霍夫变换。

 

       透过前面的检测直线、圆、广义霍夫变换,已经可以提取出霍夫变换的一个本质——给出图形的一个描述模式,比如图形点集的方程、函数、表格等,然后利用这个模式加上遍历参数空间,把属于该模式的图形点集投射到参数空间的一个点(实际的离散情况一般不会完美的集中到一点),这个点记录的是图形点数目

       广义霍夫变换之所以能处理任意形状的图形并不是找到了可以表示任意图形的方程(这是不可能的),而是使用表的形式描述一种图形,把图形边缘点坐标保存在一张表中,那么该图形就确定下来了,所以其实无论是直线(其实是线段)、圆、椭圆还是其他形状的几何图形,都可以使用同一方法处理,所不同的是这时候的图形是自定义的,是实在的,而代数方程表示的模式是连续的、抽象的,圆的方程只有一种,但自定义的圆却是无穷的,只要你认为它足够圆了就可以。当然两种表示都会有各自的优势和局限。有了表之后就需要找到一种可以把图形点集投射到参数空间的一点的转换算法,例如直线和圆霍夫变换通过方程(函数)及遍历把点集进行投射,使得属于某直线或圆的点集中到一个点;那么仅有一张描述图形边缘坐标点的表如何进行投射呢?我们可以把这张表看作是模板,进行模板匹配,大部分的点匹配成功也就可以理解为这些点都投射到一个点上,不过这时候不需要再搜索参数空间峰值了,这种模式可以认为是参数间没有任何关联,所以是完全的遍历。但有旋转加上缩放的情况模板匹配型的霍夫变换是十分耗时的,也可以想象成因为参数不相关所以增加遍历搜索时间。Ballard (1981) 的广义霍夫变换最精妙之处在于为参数增加了两个关联,使得有平移和旋转(无缩放)的情况只需要遍历一个参数,三个参数分别是图形的中心坐标(横纵),旋转角度(相对参考图形),Ballard 的算法预先把参考图形边缘点对中心的径向量保存起来,利用待搜索图形边缘点的梯度方向(用相对坐标轴的角度表示)作为索引找到相应的径向量,加上该量后就完成了投射,所以要遍历的参数只有旋转角度,所以说有两个关联。当然如果加上缩放就要遍历两个参数,这也只是和霍夫检测圆的规模一样而已。这种广义霍夫变换的图形表不再是直接保存坐标,而是边缘点的梯度加上径向量,给出了这些量同样的也就能够表示出一种图形了。然而这种广义霍夫变换也是有缺陷的,不少后来者提出了改进方法,这不在本文讨论范围。

 

      再来强调一次,霍夫变换就是通过图形的一种表示模式,加上一种转换方法,把图形的点集投射到一个点上以便检测。我们已经能够知道,参数个数越少,需要遍历的参数个数约少(关联越多),参数空间越小则处理速度越快。所以设计一种合理的转换方法非常关键。

       对于一种图形,在现实世界中可以有多种形变,线性的如:平移、旋转、透视;非线性的如:径变、切变、扭曲。每多考虑一种形变都会增加参数,比如把椭圆看作是圆的透视形变,结果多了两个参数,理论上可以去遍历每一个参数空间,但这不能满足实时性要求,所以参数之间约束(关联)越多则处理速度越快,Ballard的广义霍夫变换就是例子,这就需要发挥主观创造力了。

     其他   http://www.ilovematlab.cn/thread-117598-1-1.html


                         Hough Transform 霍夫变换检测直线 http://www.cnblogs.com/smartvessel/archive/2011/10/20/2218654.html

从理论到代码,再从代码到理论

(1)理论之通俗理解:

1.在图像中检测直线的问题,其实质是找到构成直线的所有的像素点。那么问题就是从找到直线,变成找到符合y=mx+c的所有(x,y)的点的问题。

2.进行坐标系变化y=mx+c,变成c=-xm+b。直线上的点(x1,y1),在转换坐标系后为一条直线。这个原理应该是高中的。

  以一般化视角串联霍夫变换,从直线到圆再到广义霍夫变换_第2张图片

3.直线上每一个点在MC坐标系中都表现为直线,而且,这些直线都相交于一个点,(m,c)。找到所有点的问题,转变为寻找直线的问题。

4.对于图像中的每一个点,在MC坐标系中对应着很多的直线。找到直线的交点,就对应着找到图像中的直线。

以一般化视角串联霍夫变换,从直线到圆再到广义霍夫变换_第3张图片

实际在使用这一原理的时候,不是采用直线的斜率和截距公式,而是用

以一般化视角串联霍夫变换,从直线到圆再到广义霍夫变换_第4张图片

如何实现:

1.将θ角在-90度到90度的范围里,划分为很多区间,对所有的像素点(x,y)在所有θ角的时候,求出ρ.从而累加ρ值出现的次数。高于某个阈值的ρ就是一个直线。

2.  这个过程就类似于如下一个二维的表格,横坐标就是θ角,ρ就是到直线的最短距离。

以一般化视角串联霍夫变换,从直线到圆再到广义霍夫变换_第5张图片

横坐标θ不断变换,对于所有的不为0的像素点,计算出ρ,找到ρ在坐标(θ,ρ)的位置累加1.

3.       上图中局部最大的就是找到的直线的θ和ρ的值。

 

for( ang = 0, n = 0; n < numangle; ang += theta, n++ )
{
	tabSin[n] = (float)(sin(ang) * irho);
	tabCos[n] = (float)(cos(ang) * irho);
}

// stage 1. fill accumulator
for( i = 0; i < height; i++ )
	for( j = 0; j < width; j++ )
	{
		if( image[i * step + j] != 0 )
			for( n = 0; n < numangle; n++ )
			{
				r = cvRound( j * tabCos[n] + i * tabSin[n] );
				r += (numrho - 1) / 2;
				accum[(n+1) * (numrho+2) + r+1]++;
			}
	}

// stage 2. find local maximums
	for( r = 0; r < numrho; r++ )
		for( n = 0; n < numangle; n++ )
		{
			int base = (n+1) * (numrho+2) + r+1;
			if( accum[base] > threshold &&
				accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
				accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )
				sort_buf[total++] = base;
		}

// stage 3. sort the detected lines by accumulator value
  icvHoughSortDescent32s( sort_buf, total, accum );

// stage 4. store the first min(total,linesMax) lines to the output buffer
  linesMax = MIN(linesMax, total);
  scale = 1./(numrho+2);
  for( i = 0; i < linesMax; i++ )
	{
		CvLinePolar line;
		int idx = sort_buf[i];
		int n = cvFloor(idx*scale) - 1;
		int r = idx - (n+1)*(numrho+2) - 1;
		line.rho = (r - (numrho - 1)*0.5f) * rho;
		line.angle = n * theta;
		cvSeqPush( lines, &line );
	}




你可能感兴趣的:(以一般化视角串联霍夫变换,从直线到圆再到广义霍夫变换)