霍夫变换同样可以检测图像中是否存在圆形,其检测方法与检测直线的方式相同,都是将图像空间x-y直角坐标系中的像素投影到参数空间中,之后寻找是否存在交点。在检测圆形的霍夫变换中圆形的数学描述形式如式(7.7)所示。
假设图像上中心像素点和圆的半径已知,根据已知量和式(7.7)可以将图像空间x-y直角坐标系中的像素投影到参数空间中,图7-12给出了这种霍夫变换的示意图。
图7-12 圆形霍夫变换示意图
OpenCV 4中提供了利用霍夫变换检测图像中是否存在圆形的HoughCircles()函数,该函数的函数原型在代码清单7-9中给出。
代码清单7-9 HoughCircles()函数原型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 )
- image:待检测圆形的输入图像,数据类型必须是CV_8U的单通道灰度图像。
- circles:检测结果的输出量,每个圆形用三个参数描述,分别是圆心的坐标和圆的半径
- method:检测圆形的方法标志,目前仅支持HOUGH_GRADIENT方法。
- dp:离散化时分辨率与图像分辨率的反比。
- minDist:检测结果中两个圆心之间的最小距离。
- param1:使用HOUGH_GRADIENT方法检测圆形时,传递给Canny边缘检测器的两个阈值的较大值。
- param2:使用HOUGH_GRADIENT方法检测圆形时,检测圆形的累加器阈值,阈值越大检测的圆形越精确。
- minRadius:检测圆的最小半径
- maxRadius:检测圆的最大半径。
该函数可以检测灰度图像中是否存在圆形,与前面介绍的霍夫变换相关函数不同,该函数会调用Canny边缘检测进行边缘检测,因此在检测圆形时不需要对灰度图像进行二值化,直接输入灰度图像即可。函数中第一个参数是输入图像,图像的数据类型必须是CV_8UC1。函数第二个参数是圆形的检测结果,存放在vector类型的变量中,每个圆形的检测结果变量类型是Vec3f,其中前2个参数是圆形的中心坐标,第3个参数是圆形的半径。第三个参数是检测圆形的方法标志,目前仅支持HOUGH_GRADIENT方法。第四个参数是离散化时分辨率与图像分辨率的反比。例如,如果dp = 1,则图像离散化后具有与输入图像相同的分辨率,如果dp = 2,则图像离散化后宽度和高度都是原图像的一半。第五个参数是检测结果中两个圆心之间的最小距离,如果参数太小,除了真实的圆形之外,可能错误地检测到多个相邻的圆圈;如果参数太大,可能会遗漏一些圆形。第六个参数是Canny检测边缘时两个阈值的较大值,较小阈值默认为较大值的一半。第七个参数是累加器阈值,阈值越大检测的圆形越精确。最后两个参数是检测圆形半径的取值范围,半径的最小值需要大于等于0,默认值为0;半径的最大值可以任意取值,当取值小于等于0时圆形半径的最大值为图像尺寸的最大值,并且检测结果只输出圆形的中心,不输出圆形的半径。
为了了解该函数的使用方法以及圆形的检测结果,在代码清单7-10中给出了利用HoughCircles()函数检测图像中是否存在圆形的示例程序,程序的输出结果在图7-13给出。
代码清单7-10 myHoughCircles.cpp圆形检测 #include #include #include using namespace cv; using namespace std; int main(){ Mat img = imread("coins.jpg"); if (img.empty()) { cout << "请确认图像文件名称是否正确" << endl; return -1; } imshow("原图", img); Mat gray; cvtColor(img, gray, COLOR_BGR2GRAY); GaussianBlur(gray, gray, Size(9, 9), 2, 2); //平滑滤波 //检测圆形 vector circles; double dp = 2; // double minDist = 10; //两个圆心之间的最小距离 double param1 = 100; //Canny边缘检测的较大阈值 double param2 = 100; //累加器阈值 int min_radius = 20; //圆形半径的最小值 int max_radius = 100; //圆形半径的最大值 HoughCircles(gray, circles, HOUGH_GRADIENT, dp, minDist, param1, param2, min_radius, max_radius); //图像中标记出圆形 for (size_t i = 0; i < circles.size(); i++) { //读取圆心 Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); //读取半径 int radius = cvRound(circles[i][2]); //绘制圆心 circle(img, center, 3, Scalar(0, 255, 0), -1, 8, 0); //绘制圆 circle(img, center, radius, Scalar(0, 0, 255), 3, 8, 0); } //显示结果 imshow("圆检测结果", img); waitKey(0); return 0; }
图7-13 myHoughCircles.cpp程序中圆形检测结果