python霍夫圆检测代码 matlab霍夫变换找圆心_霍夫变换


时间为友,记录点滴。

霍夫变换是图像变换中的经典手段之一,主要用来从图像中分离出具有某种相同特征的几何形状(如,直线,圆等)。霍夫变换寻找直线与圆的方法相比与其它方法可以更好的减少噪声干扰。经典的霍夫变换常用来检测直线,圆,椭圆等。

嗯,感觉说了等于没说。今天我们用陈述法来看待这个问题。

什么是极坐标?

如果解释这个问题,默认都了解笛卡尔坐标系(就是最常用的直角坐标系)。


python霍夫圆检测代码 matlab霍夫变换找圆心_hough变换直线检测_02

直角坐标系


直角坐标系中表示一条直线,我们一般用


表示,那么


就代表这条直线的斜率,


代表与Y轴的截距。用下图来表示:


python霍夫圆检测代码 matlab霍夫变换找圆心_hough变换检测圆matlab指令_03

y=kx+b在直角坐标系中的表示

直角坐标系下有个问题,当直线平行于Y轴的时候,斜率k的值无限大,这样不利于问题的分析,不过这难不到数学教,为了方便地表示所有的直线,牛爵爷引入极坐标:


python霍夫圆检测代码 matlab霍夫变换找圆心_霍夫变换_04

θ和ρ

在平面内取一个定点O,叫极点,引一条射线Ox,叫做极轴,再选定一个长度单位和角度的正方向(通常取逆时针方向)。对于平面内任何一点M,用ρ表示线段OM的长度(有时也用r表示),θ表示从Ox到OM的角度,ρ叫做点M的极径,θ叫做点M的极角,有序数对 (ρ,θ)就叫点M的极坐标,这样建立的坐标系叫做极坐标系。通常情况下,M的极径坐标单位为1(长度单位),极角坐标单位为rad(或°)。(来自百度百科)

是不是概念总是很难理解?有时候我真的在想大神们故意拿苛刻晦涩的定义是用来显摆的。其实看下图最好理解:


python霍夫圆检测代码 matlab霍夫变换找圆心_python霍夫圆检测代码_05

以θ和r为直角坐标系的标定轴的直线表示

我们把直线


画在直角坐标系上,从原点引线段到直线上的任一点,那么这条线段与X轴的夹角为θ, 距离为r。那么对于直线上的任一点


, 有



怎么识别直线?

设空间中有若干点,我们要判断这些点是否能构成一条直线,即为直线检测。

  1. 在图像中检测直线的问题,其实质是找到构成直线的所有的像素点。那么问题就是从找到直线,变成找到符合 的所有(x,y)的点的问题。
  2. 我们可以把公式 ,变成 。这样直线上的点 ,在k/y坐标系下就变成了一条直线。


python霍夫圆检测代码 matlab霍夫变换找圆心_直线和圆交点 halcon_06


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

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

这就是直角坐标系下的直线查找的思路转换:

找直线 => 找所有点 => 转换坐标轴 => 找直线

我们可以把这种思路推演到极坐标中(而且在实际的工程中,也是在极坐标下展开的),即


,直线上的所有点在(θ-r)坐标系下都会相相交一点:


python霍夫圆检测代码 matlab霍夫变换找圆心_hough变换直线检测_07

来自:

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

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


python霍夫圆检测代码 matlab霍夫变换找圆心_python霍夫圆检测代码_08

累加r出现的次数其实表示相交点的个数筛选

数字图像中的霍夫曼直线检测?

然而在实现的图像处理领域,图像的像素坐标P(x, y)是已知的,而r, θ则是我们要寻找的变量。如果我们能绘制每个(r, θ)值根据像素点坐标P(x, y)值的话,那么就从图像笛卡尔坐标系统转换到极坐标霍夫空间系统,这种从点到曲线的变换称为直线的霍夫变换。变换通过量化霍夫参数空间为有限个值间隔等分或者累加格子。当霍夫变换算法开始,每个像素坐标点P(x, y)被转换到(r, θ)的曲线点上面,累加到对应的格子数据点,当一个波峰出现时候,说明有直线存在。

OpenCv中的霍夫曼直线检测的算法逻辑?

  1. 读取一幅带处理二值图像,最好背景为黑色。
  2. 取得源像素数据
  3. 根据直线的霍夫变换公式完成霍夫变换,预览霍夫空间结果
  4. 寻找最大霍夫值,设置阈值,反变换到图像RGB值空间(程序难点之一)
  5. 越界处理,显示霍夫变换处理以后的图像

跟咱们之前介绍的所有小庆幸一样,OpenCV同样提供了专门的API给我们:


CV_EXPORTS_W


  • 第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的单通道二进制图像,可以将任意的源图载入进来后由函数修改成此格式后,再填在这里。
  • 第二个参数,InputArray类型的lines,经过调用HoughLines函数后储存了霍夫线变换检测到线条的输出矢量。每一条线由具有两个元素的矢量 表示,其中, 是离坐标原点((0,0)(也就是图像的左上角)的距离。 是弧度线条旋转角度(0~垂直线,π/2~水平线)。
  • 第三个参数,double类型的rho,以像素为单位的距离精度。另一种形容方式是直线搜索时的进步尺寸的单位半径。PS:Latex中/rho就表示 。
  • 第四个参数,double类型的theta,以弧度为单位的角度精度。另一种形容方式是直线搜索时的进步尺寸的单位角度。
  • 第五个参数,int类型的threshold,累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值。大于阈值threshold的线段才可以被检测通过并返回到结果中。
  • 第六个参数,double类型的srn,有默认值0。对于多尺度的霍夫变换,这是第三个参数进步尺寸rho的除数距离。粗略的累加器进步尺寸直接是第三个参数rho,而精确的累加器进步尺寸为rho/srn。
  • 第七个参数,double类型的stn,有默认值0,对于多尺度霍夫变换,srn表示第四个参数进步尺寸的单位角度theta的除数距离。且如果srn和stn同时为0,就表示使用经典的霍夫变换。否则,这两个参数应该都为正数。
  • 第八个参数,double类型的 min_theta,对于标准和多尺度Hough变换,检查线条的最小角度。必须介于0和max_theta之间。
  • 第九个参数,double类型的 max_theta, 对于标准和多尺度Hough变换,检查线条的最大角度。必须介于min_theta和CV_PI之间.
CV_EXPORTS_W


  • 第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的单通道二进制图像,可以将任意的源图载入进来后由函数修改成此格式后,再填在这里。
  • 第二个参数,InputArray类型的lines,经过调用HoughLinesP函数后后存储了检测到的线条的输出矢量,每一条线由具有四个元素的矢量(x_1,y_1, x_2, y_2) 表示,其中,(x_1, y_1)和(x_2, y_2) 是是每个检测到的线段的结束点。
  • 第三个参数,double类型的rho,以像素为单位的距离精度。另一种形容方式是直线搜索时的进步尺寸的单位半径。
  • 第四个参数,double类型的theta,以弧度为单位的角度精度。另一种形容方式是直线搜索时的进步尺寸的单位角度。
  • 第五个参数,int类型的threshold,累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值。大于阈值threshold的线段才可以被检测通过并返回到结果中。
  • 第六个参数,double类型的minLineLength,有默认值0,表示最低线段的长度,比这个设定参数短的线段就不能被显现出来。
  • 第七个参数,double类型的maxLineGap,有默认值0,允许将同一行点与点之间连接起来的最大的距离.

重点需要理解的是threshold这个参数:

霍夫空间的累加域值,图像在霍夫空间每个像素点都是一条曲线,经过的每个(r,theta)都加1,如果多个曲线都经过同一个(r,theta)相交,如果大于给定的域值,说明可能存在一条直线在霍夫空间该点!(可以结合理论部分)

好了,我们来用代码看看吧。

C++

注意点:

1. 对于一幅图,使用了Canny做边缘检测(还记得Canny的参数代表什么含义吗?)
2. Vec2f类型typedef Vec<float, 2> Vec2f;用来存储


3. 划线的时候要由霍夫曼坐标系下转换到笛卡尔坐标系,

;


4. 如果发现直线太多,可以在Canny前面做一次高斯模糊,或者调整HoughLines的threshold。


#include


python霍夫圆检测代码 matlab霍夫变换找圆心_hough变换直线检测_09


Python:

注意事项:

1. HoughLines的返回值lines,从霍夫曼坐标系转换到直角坐标系的公式
2. HoughLinesP的返回值lines,四个点的坐标。


#!/usr/bin/env python


python霍夫圆检测代码 matlab霍夫变换找圆心_直线和圆交点 halcon_10


写在后面:

对比HoughLines和HoughLinesP

  • houghlines的计算效率比较低O(n*n*m),耗时较长,而且没有检测出直线的端点。
  • 统计概论霍夫直线检测houghlinesP是一个改进,不仅执行效率较高,而且能检测到直线的两个端点。它是先随机检测出一部分直线,然后将直线上点的排查掉,再进行其他直线的检测

HoughLinesP的做法:

  • 首先仅统计图像中非零点的个数,对于已经确认是某条直线上的点就不再变换了。
  • 对所以有非零点逐个变换到霍夫空间
  • 并累加到霍夫统计表(图像)中,并统计最大值
  • 最大值与阈值比较,小于阈值,则继续下一个点的变换
  • 若大于阈值,则有一个新的直线段要产生了
  • 计算直线上线段的端点、长度,如果符合条件,则保存此线段,并mark这个线段上的点不参与其他线段检测的变换