霍夫圆变换与之前所描述的霍夫直线变换是大体上是类似的。说“大体上类似”的原因是——如果想要尝试完全类似——累加平面会被三维的累加容器所代替:在这三维中,一维是x,一维是y,另一维是圆的半径r。这就意味着需要大量的内存但速度却很慢。在OpenCV的应用中可以通过一个比较灵活的霍夫梯度法来解决圆变换的这一问题。
霍夫梯度法的原理如下。首先对图像应用边缘检测(这里用cvCanny ( )。然后,对边缘图像中每一个非0点,考虑其局部梯度(通过cvSobel( )函数计算x和Y方向的Sobel一阶导数得到梯度)。利用得到的梯度,由斜率指定的直线上的每一个点都在累加器中被累加,这里斜率是从一个指定的最小值到指定的最大值的距离。同时,标记边缘图像中每一个非0像素的位置。然后从(二维)累加器中这些点中选择候选的中心,这些中心都大于给定阈值并且大于其所有近邻。这些候选的中心按照累加值降序排列,以便于最支持像素的中心首先出现。接下来对每一个中心,考虑所有的非0像素(回想一下这个清单在早期已经建立)。这些像素按照其与中心的距离排序。从到最大半径的最小距离算起,选择非0像素最支持的一条半径。如果一个中心受到边缘图像非0像素最充分的支持,并且到前期被选择的中心有足够的距离,它将会被保留。
这个实现可以使算法执行起来更快,或许更重要的是,能够帮助解决三维累加器中其他稀疏分布问题,这个问题会产生许多噪声并使结果不稳定。另一方面,这个算法有许多需要注意的缺点。
首先,使用Sobel导数计算局部梯度——随之而来的假设是这个可以看作等同于一条局部切线—并不是一个数值稳定做法。在大多数时间这个命题可能是真的,但你可能认为这样会在输出中产生一些噪声。
其次,在边缘图像中的整个非0像素集被认为是每个中心的候选。因此,加器的阈值设置偏低,算法将要消耗比较长的时间。
第三,因为每一个中心只选择一个圆,如果有同心圆,就只能选择其中的一个。
最后,因为中心是被认为是按照与其关联的累加器的值升序排列的,并且如果新的中心过于接近以前接受的中心将不会被保留。这里有一个倾向就是当有许多同心圆或者是近似同心圆时,保留最大的一个圆。(只是个“偏见”,因为从Sobcl导数产生了噪声;若是在无穷分辨率的平滑图像,这才是确定的)。
霍夫圆变换函数evHoughCircles()与直线变换有相似的变量。输入的image也是8位的。cvHoughCircles()与cvHoughLines2()一个明显的不