天天看点

【OpenCV】霍夫变换圆检测

在直角坐标系下,圆的方程表示为

【OpenCV】霍夫变换圆检测

其中,r是圆的半径,(a, b)是圆心坐标。

那么换一种表达方式

【OpenCV】霍夫变换圆检测

因为在直角坐标系下,圆上的所有点都满足圆的方程,所以直角坐标系下的一个圆对应到abr坐标系下就是一个点。直角坐标系下经过一个点的所有圆在abr坐标系下就是一条三维曲线。那么,直角坐标系下圆上的所有点在abr坐标系下就是这么多条三维曲线交于一点。

但是在实际计算中,三维空间意味着更加复杂的运算。OpenCV对基础的霍夫圆检测做了优化,使用两轮筛选。第一轮筛选使用一个二维累加器,找出可能是圆的位置。因为圆周上像素点的梯度方向与半径的方向一致,所以对每个像素来说,累加器只对沿梯度方向的入口增加计数。一旦检测到可能的圆心,就在第二轮筛选中建立半径值范围的一维直方图,这个直方图的尖峰值就是被检测圆的半径。

在实践中,由于梯度容易受噪声的影响,因此在进行霍夫圆检测之前要先对图像进行平滑,以减少图像中可能导致误判的噪声。

OpenCV中的函数圆形

void cv::HoughCircles(InputArray image,
    OutputArray circles,
    int method,
    double dp,
    double minDist,
    double param1 = 100,
    double param2 = 100,
    int minRadius = 0,
    int maxRadius = 0 
)	
           

函数参数比较多,可能要反复调参才能得到比较好的检测效果。

cv::Mat srcImg = cv::imread("circle.jpg");
	if (srcImg.empty())
	{
		cout << "error";
		return -1;
	}
	cv::namedWindow("SRC", CV_WINDOW_AUTOSIZE);
	cv::imshow("SRC", srcImg);

	cv::Mat srcGray;
	cv::cvtColor(srcImg, srcGray, cv::COLOR_RGB2GRAY);
	cv::namedWindow("GRAY", CV_WINDOW_AUTOSIZE);
	cv::imshow("GRAY", srcGray);

	cv::Mat blurImg;
	cv::GaussianBlur(srcGray, blurImg, cv::Size(5, 5), 1.5);
	cv::namedWindow("BLUR", CV_WINDOW_AUTOSIZE);
	cv::imshow("BLUR", blurImg);

	std::vector<cv::Vec3f> circles;
	cv::HoughCircles(blurImg, circles, cv::HOUGH_GRADIENT, 2, 50, 200, 100, 25, 100);

	cv::Mat drawImg;
	srcImg.copyTo(drawImg);
	std::vector<cv::Vec3f>::const_iterator it = circles.begin();
	while (it != circles.end())
	{
		cv::circle(drawImg, cv::Point((*it)[0], (*it)[1]), (*it)[2], cv::Scalar(0, 0, 255), 2);
		++it;
	}
	cv::namedWindow("CIRCLE", CV_WINDOW_AUTOSIZE);
	cv::imshow("CIRCLE", drawImg);

	cv::waitKey(0);
           
【OpenCV】霍夫变换圆检测
【OpenCV】霍夫变换圆检测
【OpenCV】霍夫变换圆检测
【OpenCV】霍夫变换圆检测