霍夫变换检测圆形原理分析

时间:2024-11-11 08:29:40

上一篇博客中简要描述了一下自己对霍夫变换检测直线的原理理解,现在说一下检测圆形的原理。


其实检测圆形和检测直线的原理差别不大,只不过直线是在二维空间,因为y=kx+b,只有k和b两个*度。而圆形的一般性方程表示为(x-a)²+(y-b)²=r²。那么就有三个*度圆心坐标a,b,和半径r。这就意味着需要更多的计算量,而OpenCV中提供的cvHoughCircle()函数里面可以设定半径r的取值范围,相当于有一个先验设定,在每一个r来说,在二维空间内寻找a和b就可以了,能够减少计算量。

具体步骤如下:

1.对输入图像进行边缘检测,获取边界点,即前景点。

2.假如图像中存在圆形,那么其轮廓必定属于前景点(此时请忽略边缘提取的准确性)。

3.同霍夫变换检测直线一样,将圆形的一般性方程换一种方式表示,进行坐标变换。由x-y坐标系转换到a-b坐标系。写成如下形式(a-x)²+(b-y)²=r²。那么x-y坐标系中圆形边界上的一点对应到a-b坐标系中即为一个圆。

4.那x-y坐标系中一个圆形边界上有很多个点,对应到a-b坐标系中就会有很多个圆。由于原图像中这些点都在同一个圆形上,那么转换后a,b必定也满足a-b坐标系下的所有圆形的方程式。直观表现为这许多点对应的圆都会相交于一个点,那么这个交点就可能是圆心(a, b)。

5.统计局部交点处圆的个数,取每一个局部最大值,就可以获得原图像中对应的圆形的圆心坐标(a,b)。一旦在某一个r下面检测到圆,那么r的值也就随之确定。


以下面的图片为例,调用OpenCV中的cvHoughCircles()进行圆形的检测,左边为原图,右边为检测结果,圆形都被圈出。

              

附上代码:

#include""
#include""
#include<>
using namespace cv;

void main()
{
	IplImage* srcImg=cvLoadImage("", CV_LOAD_IMAGE_GRAYSCALE);

	CvMemStorage* storage= cvCreateMemStorage(0);
	cvSmooth(srcImg, srcImg, CV_GAUSSIAN, 5, 5);
	
	//函数范围值为指向图像序列的指针
	CvSeq* results=cvHoughCircles(srcImg, storage, CV_HOUGH_GRADIENT, 2,srcImg->width/10);

	for (int i=0; i<results->total; i++)
	{
		float* p=(float*) cvGetSeqElem(results, i);  //依次获取图像序列中的图像数据
		CvPoint pt=cvPoint(cvRound(p[0]), cvRound(p[1]));  //获取圆心坐标
		cvCircle(srcImg, pt, cvRound(p[2]), CV_RGB(0xff, 0xff, 0xff), 3, 8);  //在图片中将圆形画出来
	}

	cvNamedWindow("Img", 1);
	cvShowImage("Img", srcImg);

	cvWaitKey(-1);

	cvReleaseImage(&srcImg);
	cvDestroyAllWindows();
}