使用霍夫变换检测图像中的直线,圆等图形是利用图形函数的从直角坐标系到极坐标系的转换。
比如检测直线中,直线方程y = k * x + b , 直线上的所有点都对应着参数( k , b),
给定一个点(x0 , y0)我们能够得到通过这个点的所有直线的参数(k , b),易知同一条直线上的点对应的参数(k , b)是相同的
利用此信息,我们建立k , b 的累加器,依次计算图像中提取出的边界点,计算每个点可能对应的k , b 把相应的累加器项加一
最后求出累加器中的局部峰值,若峰值大于给定的阈值就得到一条(k , b)所确定的直线。
为了便于计算我们可以使用直线公式:
P = x *cos(thea) + y * sin(thea) ;
P :图像左上角(原点)到直线的距离
thea:原点到直线的垂线和X轴正向的夹角(沿着顺时针方向)
注意:图像中X轴从左向右增加Y轴从上向下增加
检测圆也使用相同的原理:
圆的公式为:
x = x0 + r * cos(thea) ;
y = y0 + r*sin(thea) ;
1、标准霍夫变换:
标准霍夫变换需要把点(x ,y )投射到三维空间内(x0 , y0 , r) , 因此累加器需要很大的空间,运算量巨大,不适用实时性的要求。
2、随机霍夫变换
随机选择三个点,三个点可以确定一个圆实现多对一,减少了内存的消耗 ,节约了大量时间
步骤:
1、构造边缘点集D ,初始化参数链表P= NULL ,循环控制k = 0
2、 从D中随机选择三个点d1 , d2 , d3
3、计算由d1 , d2 , d3 三点确定的圆 ,若能确定一个圆 参数为p ,转第4步 ;否则转
4、检查链表P,若有一项||pc-p|| < 给定的最小误差,转6;否则,转5
5、把p插入链表,其值value 置1
6、把pc 的value值加1 , 若小于阈值转7 ; 否则,转8
7、k = k + 1 ,若k > Kmax,退出,否则转2
8、pc作为候选圆参数,若其确定的圆上对应的边界点数 > 最小值Votes ,则pc所确定的为真圆 , 转9 ;否则,为假圆,把pc从链表P中剔除 , 转2 ;
9、判定已经检测到的圆是否达到规定数目,若是,退出,否则 , 将落在pc对应圆上的点从D中剔除 , P置空 , k = 0 ,转2 ;
3、随机霍夫变换的改进
利用提取边界时得到的梯度信息检测圆 ,方法二中利用随机的三个点确定的圆有许多是假圆,这造成了许多无效的累积,增长了链表,多消耗了内存。使用梯度信息进一步增加准确性,减少无效累积,缩短了链表。
1、构建边缘点集D及梯度信息, 参数链表P= NULL, 循环控制 k = 0 ;
2、随机从D中选取两个点(x0 , y0 ) , (x1 , y1)
3、计算两点梯度方向分别和两点连线的中垂线的交点(x3 , y3) , (x4 ,y4)
判断两点是否重合(注意误差),重合就算参数p,转4 ,否则 , 转7
4、在P中寻找满足||pc-p|| < 指定误差 ,转6 , 否则,转5
5、把p 插入链表P中,其Value置1
6、把pc对应的value加1 , 若大于阈值,转8 ,否则,转7
7、 k = k + 1 ,若k > Kmax ,程序退出,否则转2
8、pc 所确定的圆作为候选圆 , 候选圆上对应的点 > 指定的最小点数,转9 ; 否则,为假圆 , 从P中出去pc ,转2
9、pc 为真圆,看检测的圆数目是否达到要求, 若是,退出; 否则,把pc圆上对应的点从D中剔除,P置NULL, k = 0 ,转2