霍夫变换是检测直线或者圆的一种比较简单的方法。霍夫变换检测直线是比较简单的,做完以后是一个二维平面上的许多曲线,通过统计平面上交点的个数,就可以得出哪些点事处于同一条直线上的。
霍夫圆变换是稍微难理解的。原理和霍夫直线变换原理大致是相同的,不过其每个点对应的二维空间被3位空间所取代(圆心x,y以及半径r),如果用完全相同的方法去映射的话,累加平面会被三维上的一个容器取代,这样不仅要消耗大量的内存,运算速度也很低。
opencv里是采用了一种叫做“霍夫梯度法”的方法来计算霍夫圆变换的问题。
具体算法分为以下几个步骤:
1:边缘检测,这个比如opencv里霍夫变换用的是canny边缘检测。
2:对于边缘图像的非零点:考虑其局部梯度,用sobel函数来计算其梯度,关注其方向。
3:利用得到的梯度,在梯度指定的直线上的每一个点都在累加器中被累加。
第三步是关键的一步,这一步的作用是找圆心。比如下面这个圆是一个边缘,我们把边缘上的每一点的梯度方向所在直线上的点都累加(蓝线)。这样的话,我们新建的累加平面和原图的大小是一样的(事实上opencv函数的第四个参数可以设置这个图像的大小,那里叫做累加器图像的分辨率与原图分辨率之比的倒数,比如取2的话就表示累加图分辨率是原图分辨率的一半),这样对于每一个边缘点都进行操作之后,累加平面上值越大的地方就表示越可能是圆心,累加平面上值越大的地方表示了足够多的半径在这里相交。我们把这些点作为圆心的候选点(从多至少)
4.对于每一个中心,考虑边缘图的每一个非零元素,按照距离远近来排序,从到最大半径的最小半径(这个可以手动设置,opencv里也有设置的值,也可默认则在原图中穷举搜索)统计支持此中心的像素个数,越多的像素落到某个半径上,则说明此处越有可能存在一个圆。选择支持像素最多的一个半径来作为此圆心下的一个圆。
5:获得圆心和半径之后,标记出来即可。
对于比较简单的情况,这种方法的效率还算比较高的,但是对于复杂的图像,漏检率很高,效率也很低,有一幅图像跑了二十多分钟才跑出来,而且对于参数设置也比较敏感,图像简单时可以用下,若是比较复杂的图像,不推荐采用这种法法。