霍夫变换检测直线
霍夫变换(Hough Transform)是图像处理中的一种特征提取技术,该过程在一个参数空间中通过计算累积结果的局部最大值得到一个符合该特定形状的集合最为霍夫变换的结果。霍夫变换运用两个坐标空间之间的变换将在一个空间中具体相同形状的曲线或直线映射到另一个坐标空间的一个点上形成峰值,从而把检测任意形状的问题转换为统计峰值问题。
1)平面坐标的点 <=> 极坐标(平面化)的曲线
所谓极坐标平面化是指,将 ρ-θ的关系像x-y那样在平面内展开。
公式推导:x-y坐标坐标中的点代入极坐标ρ-θ中得
2)极坐标的点 <=> 平面坐标的直线
公式推导:ρ-θ极坐标中的点(ρ0, θ0),代入平面坐标x-y中得
由此可知,极坐标中的一个定点(ρ0, θ0), 对应于平面坐标内的一条直线。若极坐标中有N条曲线相交于一点(如下左图),则说明在平面坐标中,该点对应的直线包含N条曲线对应的N个点,也即这N个点组成了一条直线。
上面左图中,是平面坐标中三个点(8,6),(4,9),(12,3)分别对应的三条曲线。
因此,霍夫变换的目的是将平面坐标内的直线检测,转换为极坐标内的交点检测,显然寻找一个交点要比寻找直线(实际上是寻找许多点)容易得多了。
3)霍夫投票
对于求交点霍夫投票的方法此时就登场了,对于霍夫空间上图像的每一个点都用字典来表示他们,字典索引就用霍夫空间得坐标(ρ, θ)来检索,字典的值表示该坐标上有多少个曲线点(字典的学名叫作累加器:accumulator)。
算法实现步骤伪代码如下:
For each edge pixel (x,y) in image
For θ= -90 to 90
ρ= x cosθ+ y sin θ
++ H(iθ, jρ);
end
end
圆和椭圆也都是类似步骤,只不过圆有三个参数,而椭圆有5个参数,计算量更大。
实现霍夫变换流程:
1)将图像转换为 灰度图 进行 边缘检测并二值化 预处理
2)通过寻找非零点的坐标确定数据点进行霍夫变换
霍夫变换检测圆
根据以上霍夫变换原理分析可知,对图像进行空间变换,利用图像全局特征将边缘像素连接起来组成区域封闭曲线,把图像空间变换为参数空间,使变换的结果更易识别和检测,以达到检测图像边缘的目的。
霍夫变换的实质就是对图像进行坐标变换,把平面坐标变换为参数坐标,使变换的结果更易识别和检测。
1)原理分析
圆在直角坐标系中的数学表达式:R^2=(x-a)^2+(y-b)^2
圆在极坐标系中的数学表达式:x=x0+Rcosθ
y=y0+Rcosθ
数学原理分析:根据极坐标转换,假设已知半径R,对于图像空间上的每一点以R为半径旋转360度,即θ=(0,360),则中心处点的坐标累加值必定最大。
其中(a,b)为圆的中心坐标,r为圆的半径。这样霍夫的参数空间就变成了一个三维参数空间。
把x-y平面上的圆转换到a-b-r参数空间,则图像空间中点(x,y)在参数空间上对应的图像是一个三维锥面,如下图所示:
同理,过图像空间中任意一点对应于参数空间中的一个三维锥面。因此,圆上的所有点对应的参数空间图像上,必然在高度为R上交于一点(a,b,r)。如下图所示:
算法流程
#
2)霍夫变换梯度法(根据每个点的模向量来找到圆心,这样三维的累加平面就转化为二维累加平面)
思路:
第一步:对图像应用边缘检测
第二步:对边缘二值图像中的每一个非零点,考虑其局部梯度,即用Sobel算子函数来计算x方向和y方向的Sobel一阶导数得到梯度。
第三步:遍历边缘二值图中的非零点,沿着梯度方向和反方向画线段(梯度方向为圆弧的法线方向,即半径方向),线段的起点和长度由参数允许的半价区间决定。将线段经过的点咋子累加器中记数
第四步:对累加器中的点从大到小排序,记数越大越有可能成为圆心。
#
源码及其简单实现:
标准霍夫变换HoughLines
调用:void HoughLines( InputArray image, OutputArray lines,
double rho, double theta, int threshold,
double srn = 0, double stn = 0,
double min_theta = 0, double max_theta = CV_PI );
参数1:输入单通道的二值图像;
参数2:经过函数HoughLines储存了霍夫变换检测到直线的输出矢量;即需要提取定义一个矢量结构lines用于存放:vector<Vec2f> lines; /<Vec2f>----Vec<float,2>。
参数3:double类型的rho,以像素为单位的距离精度。
参数4:以弧度表示的累加器的角度分辨率。
参数5:阈值累加器阈值参数。 即识别某部分为图中的直线时,它在累加平面中必须达到的值,大于此阈值的线段才可以被检测通过返回到结果中。
参数6:double类型的srn,有默认值0
参数7:double类型的stn,有默认值0
double rho, double theta, int threshold,
double minLineLength = 0, double maxLineGap = 0 );
参数1:输入单通道的二值图像;
参数2:经过函数HoughLineP储存了霍夫变换检测到直线的输出矢量;即需要提取定义一个矢量结构lines用于存放:vector<Vec4i> lines; /<Vec4i>----Vec<int,4>。
参数3:double类型的rho,以像素为单位的距离精度。
参数4:以弧度表示的累加器的角度分辨率。
参数5:阈值累加器阈值参数。 即识别某部分为图中的直线时,它在累加平面中必须达到的值,大于此阈值的线段才可以被检测通过返回到结果中。
参数6:最低线段长度。有默认值0;
参数7:允许同一行点与点之间连接起来的最大距离;默认0;
霍夫圆变换HoughCircles
调用:void cv::HoughCircles( InputArray _image, OutputArray _circles,
int method, double dp, double min_dist,
double param1, double param2,
int minRadius, int maxRadius );
参数1:8位灰度单通道。
参数2:经过函数HoughCircles储存了霍夫变换检测到的圆的矢量。
参数3:int类型的method,即使用的检测方法。(梯度法:HOUGH_GRADIENT)
参数4:double类型的dp,用来检测圆心的累加器图像分辨率于输入图像之比的倒数。如果dp=2,累加器便有输入图像一半那么大的宽度和高度。
参数5:double类型的minDist,为霍夫变换检测到的圆的圆心之间的最小距离。
参数6:double类型的param1,默认值100。表示传递给cannyu边缘检测算子的高阈值,而低阈值为高阈值的一半。
参数7:double类型的param2,默认值100.表示检测阶段圆心的累加器阈值。
参数8:int类型的minRadius,默认值为0,表示圆半径的最小值。
参数9:int类型的maxRadius,默认值为0,表示圆半径的最大值。
1 //-----------------------------------【头文件包含部分】--------------------------------------- 2 // 描述:包含程序所依赖的头文件 3 //---------------------------------------------------------------------------------------------- 4 #include <opencv2/opencv.hpp> 5 #include <opencv2/imgproc/imgproc.hpp> 6 7 //-----------------------------------【命名空间声明部分】--------------------------------------- 8 // 描述:包含程序所使用的命名空间 9 //----------------------------------------------------------------------------------------------- 10 using namespace cv; 11 //-----------------------------------【main( )函数】-------------------------------------------- 12 // 描述:控制台应用程序的入口函数,我们的程序从这里开始 13 //----------------------------------------------------------------------------------------------- 14 int main() 15 { 16 //【1】载入原始图和Mat变量定义 17 Mat srcImage = imread("yuan.png"); //工程目录下应该有一张名为1.jpg的素材图 18 Mat midImage, dstImage;//临时变量和目标图的定义 19 20 //【2】显示原始图 21 imshow("【原始图】", srcImage); 22 23 //【3】转为灰度图,进行图像平滑 24 cvtColor(srcImage, midImage, CV_BGR2GRAY);//转化边缘检测后的图为灰度图 25 GaussianBlur(midImage, midImage, Size(9, 9), 2, 2); 26 27 //【4】进行霍夫圆变换 28 vector<Vec3f> circles;//保存矢量 29 HoughCircles(midImage, circles, CV_HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0); 30 31 //【5】依次在图中绘制出圆 32 for (size_t i = 0; i < circles.size(); i++) 33 { 34 Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); 35 int radius = cvRound(circles[i][2]); 36 //绘制圆心 37 circle(srcImage, center, 3, Scalar(0, 255, 0), -1, 8, 0); 38 //绘制圆轮廓 39 circle(srcImage, center, radius, Scalar(155, 50, 255), 3, 8, 0); 40 //Scalar(55,100,195)参数中G、B、R颜色值的数值,得到想要的颜色 41 } 42 43 //【6】显示效果图 44 imshow("【效果图】", srcImage); 45 46 waitKey(0); 47 48 return 0; 49 }
参考文献:霍夫变换——空间坐标的转换