在直角坐标系下,圆的方程表示为
其中,r是圆的半径,(a, b)是圆心坐标。
那么换一种表达方式
因为在直角坐标系下,圆上的所有点都满足圆的方程,所以直角坐标系下的一个圆对应到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);