OpenCV图像处理开发实战(12) -- 霍夫变换与直线圆检测

1、霍夫变换原理

Hough变换的基本原理在于利用点与线的对偶性,将原始图像空间的给定的曲线通过曲线表达形式变为参数空间的一个点。这样就把原始图像中给定曲线的检测问题转化为寻找参数空间中的峰值问题。也即把检测整体特性转化为检测局部特性。比如直线、椭圆、圆、弧线等。

(1)直线检测

OpenCV图像处理开发实战(12) -- 霍夫变换与直线圆检测_第1张图片
画一条直线,要求出这条直线所在的位置。直线的方程可以用y=kx+b 来表示,其中k和b是参数,分别是斜率和截距。过某一点(x0,y0)的所有直线的参数都会满足方程y0=kx0+b。即点(x0,y0)确定了一族直线。方程y0=kx0+b在参数k–b平面上是一条直线,(也可以是方程b=-x0k+y0对应的直线)。这样,图像x–y平面上的一个前景像素点就对应到参数平面上的一条直线。设图像上的直线是y=x, 我们先取上面的三个点:A(0,0), B(1,1), C(22)。可以求出,过A点的直线的参数要满足方程b=0, 过B点的直线的参数要满足方程1=k+b, 过C点的直线的参数要满足方程2=2k+b, 这三个方程就对应着参数平面上的三条直线,而这三条直线会相交于一点(k=1,b=0)。 同理,原图像上直线y=x上的其它点(如(3,3),(4,4)等) 对应参数平面上的直线也会通过点(k=1,b=0)。这个性质就为我们解决问题提供了方法,就是把图像平面上的点对应到参数平面上的线,最后通过统计特性来解决问题。假如图像平面上有两条直线,那么最终在参数平面上就会看到两个峰值点,依此类推。

Hough变换思想为:在原始图像坐标系下的一个点对应了参数坐标系中的一条直线,同样参数坐标系的一条直线对应了原始坐标系下的一个点,然后,原始坐标系下呈现直线的所有点,它们的斜率和截距是相同的,所以它们在参数坐标系下对应于同一个点。这样在将原始坐标系下的各个点投影到参数坐标系下之后,看参数坐标系下有没有聚集点,这样的聚集点就对应了原始坐标系下的直线。
在实际应用中,y=kx+b形式的直线方程没有办法表示x=c形式的直线(这时候,直线的斜率为无穷大)。所以实际应用中,是采用参数方程p=xcos(theta)+y*sin(theta)。这样,图像平面上的一个点就对应到参数p—theta平面上的一条曲线上,其它的还是一样。

(2)圆弧的检测

其实Hough变换可以检测任意的已知表达形式的曲线,关键是看其参数空间的选择,参数空间的选择可以根据它的表达形式而定。比如圆的表达形式为 ,所以当检测某一半径的圆的时候,可以选择与原图像空间同样的空间作为参数空间。那么圆图像空间中的一个圆对应了参数空间中的一个点,参数空间中的一个点对应了图像空间中的一个圆,圆图像空间中在同一个圆上的点,它们的参数相同即a,b相同,那么它们在参数空间中的对应的圆就会过同一个点(a,b),所以,将原图像空间中的所有点变换到参数空间后,根据参数空间中点的聚集程度就可以判断出图像空间中有没有近似于圆的图形。如果有的话,这个参数就是圆的参数。

对于圆的半径未知的情况下,可以看作是有三个参数的圆的检测,中心和半径。这个时候原理仍然相同,只是参数空间的维数升高,计算量增大。图像空间中的任意一个点都对应了参数空间中的一簇圆曲线。 ,其实是一个圆锥型。参数空间中的任意一个点对应了图像空间中的一个圆。

2、霍夫变换相关函数

(1)HoughLines()函数

void HoughLines(
InputArray image,
OutputArray lines, // 输出的直线坐标
double rho, // 像素扫描步长
double theta, // 角度步长,一般取值为CV_PI/180
int threshold,// 阈值,相交的极点坐标的像素点数,才作为一条直线
double srn = 0,// 是否应用多尺度的霍夫变换,0表示经典的 霍夫变换
double stn = 0,// 是否应用多尺度的霍夫变换,0表示经典的 霍夫变换
double min_theta = 0, // 表示角度扫描范围。
double max_theta = CV_PI );

(2)HoughLinesP()函数

void HoughLinesP(
InputArray image,
OutputArray lines, // 输出的直线坐标
double rho, // 像素扫描步长
double theta, // 角度步长,一般取值为CV_PI/180
int threshold,// 阈值,相交极点坐标的像素点数,才作为一条直线
double minLineLength = 0, // 最小的直线长度,
double maxLineGap = 0 // 同一方向上两条线段判定为一条线段的最大允许间隔(断裂),超过了设定值,则把两条线段当成一条线段,值越大,允许线段上的断裂越大,越有可能检出潜在的直线段
);

(3)HoughCircles()函数

void HoughCircles(
InputArray image,
OutputArray circles,
int method, // 使用的检测方法(HOUGH_GRADIENT)
double dp, // 图像的分辨率
double minDist, // 为霍夫变换检测到的圆的圆心之间的最小距离
double param1 = 100, // 它是第三个参数method设置的检测方法的对应的参数,表示传递给canny边缘检测算子的高阈值
double param2 = 100, // 也是第三个参数method设置的检测方法的对应的参数,表示在检测阶段圆心的累加器阈值
int minRadius = 0, // 表示圆半径的最小值
int maxRadius = 0 // 表示圆半径的最大值
);

3、代码演示

	cvtColor(srcImg1, grayImg, CV_BGR2GRAY);

	Mat CannyImg;

	Canny(grayImg, CannyImg, 50,150);

	vector<Vec4f> lines;
	HoughLinesP(CannyImg, 
		lines, 
		1.0, 
		CV_PI/180, 
		100, 
		10, // 最小线长
		15   // 线段最大间隔(充许断线,线之间缝隙小于此值,当为一条线)
		);
	Scalar color(0, 0, 255);

	for (int i = 0; i < lines.size(); i++)
	{
		Vec4f v = lines[i];
		line(srcImg1, Point(v[0], v[1]), Point(v[2], v[3]), color);
	}

	vector<Vec3f> circles;
	HoughCircles(CannyImg, circles, CV_HOUGH_GRADIENT, 1, 10 , 100, 60);
	Scalar color1(0, 150, 255);
	for (int i = 0; i < circles.size(); i++)
	{
		Vec3f v = circles[i];
		circle(srcImg1, Point(v[0], v[1]), v[2], color1);
	}

	imshow(src_file_name1, srcImg1);// 显示

运行效果图:
OpenCV图像处理开发实战(12) -- 霍夫变换与直线圆检测_第2张图片

4、工程项目源码下载

本文源码在Debug–x64下编译
ZIP包中包含开发环境,下载解码可以直接编译运行。

下载源码

你可能感兴趣的:(OpenCV,程序人生)