Hough变换检测圆

原理:

       

我们要从一副图像中检测出半径以知的圆形来。这个问题比前一个还要直观。我们可以取和图像平面一样的参数平面,以图像上每一个前景点为圆心,以已知的半径在参数平面上画圆,并把结果进行累加。最后找出参数平面上的峰值点,这个位置就对应了图像上的圆心。在这个问题里,图像平面上的每一点对应到参数平面上的一个圆。

    把上面的问题改一下,假如我们不知道半径的值,而要找出图像上的圆来。这样,一个办法是把参数平面扩大称为三维空间。就是说,参数空间变为x--y--R三维,对应圆的圆心和半径。图像平面上的每一点就对应于参数空间中每个半径下的一个圆,这实际上是一个圆锥。最后当然还是找参数空间中的峰值点。不过,这个方法显然需要大量的内存,运行速度也会是很大问题。

    有什么更好的方法么?我们前面假定的图像都是黑白图像(2值图像),实际上这些2值图像多是彩色或灰度图像通过边缘提取来的。我们前面提到过,图像边缘除了位置信息,还有方向信息也很重要,这里就用上了。根据圆的性质,圆的半径一定在垂直于圆的切线的直线上,也就是说,在圆上任意一点的法线上。这样,解决上面的问题,我们仍采用2维的参数空间,对于图像上的每一前景点,加上它的方向信息,都可以确定出一条直线,圆的圆心就在这条直线上。这样一来,问题就会简单了许多。


代码:

	// 加载原图  
	IplImage *pSrcImage = cvLoadImage("C:\\Users\\徐图之\\Desktop\\33.bmp", -1);
	IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
	cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY);
	//cvSmooth(pGrayImage, pGrayImage);  
	// 圆检测(灰度图)  
	CvMemStorage *pcvMStorage = cvCreateMemStorage();
	double fMinCircleGap = pGrayImage->height / 40;
	CvSeq *pcvSeqCircles = cvHoughCircles(pGrayImage, pcvMStorage, CV_HOUGH_GRADIENT, 1.8, fMinCircleGap);
	//每个圆由三个浮点数表示:圆心坐标(x,y)和半径  
	// 绘制直线  
	IplImage *pColorImage = cvCreateImage(cvGetSize(pGrayImage), IPL_DEPTH_8U, 3);
	cvCvtColor(pGrayImage, pColorImage, CV_GRAY2BGR);
	for (int i = 0; i < pcvSeqCircles->total; i++)
	{
		float* p = (float*)cvGetSeqElem(pcvSeqCircles, i);
		CvPoint pt = cvPoint(cvRound(p[0]), cvRound(p[1]));
		cvCircle(pColorImage, pt, cvRound(p[2]), CV_RGB(255, 0, 0), 2);
	}

	cvNamedWindow("pstrWindowsSrcTitle", CV_WINDOW_AUTOSIZE);
	cvShowImage("pstrWindowsSrcTitle", pGrayImage);
	cvNamedWindow("Name", CV_WINDOW_AUTOSIZE);
	cvShowImage("Name", pColorImage);
	cvWaitKey(0);
	cvReleaseMemStorage(&pcvMStorage);
	cvDestroyWindow("pstrWindowsSrcTitle");
	cvDestroyWindow("pstrWindowsLineName");
	cvReleaseImage(&pGrayImage);
	cvReleaseImage(&pColorImage);

cvHoughCircles这个函数的函数原形如下:
CVAPI(CvSeq*) cvHoughCircles(
  CvArr* image, void* circle_storage,
  int method,
  double dp,
  double min_dist,
  double param1 CV_DEFAULT(100),
  double param2 CV_DEFAULT(100),
  int min_radius CV_DEFAULT(0),
  int max_radius CV_DEFAULT(0)
);

可以看出cvHoughCircles与上一章的cvHoughLines2函数比较类似,因此讲下部分参数的意思就可以了:
第二个参数表示Hough变换方式,目前只能用CV_HOUGH_GRADIENT。
第三个参数表示寻找圆弧圆心的累计分辨率,通常设置成1就可以了,如果检测不出来,可以设置大一点
第四个参数表示两个不同圆之间的最小距离,由于是按圆心来计算距离的,因此对同心圆的检测就无能为力了。
注意,圆检测函数可以使用灰度图。


你可能感兴趣的:(Hough变换检测圆)