在直角坐标系下,圓的方程表示為
其中,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);