资讯动态

OpenCV 霍夫圆变换(Hough Circle Transform)实战:用 HoughCircles 精确检测图像中的圆形目标

发布时间:2026/9/7 5:26:24 来源:尧图企业网站定制
OpenCV 霍夫圆变换Hough Circle Transform实战用 HoughCircles 精确检测图像中的圆形目标【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv本篇技术指南基于 OpenCV 官方教程 hough_circle.markdown 展开系统讲解霍夫圆变换的数学原理与 OpenCV 中HoughCircles()的完整用法涵盖灰度化、中值滤波去噪、参数调优到结果绘制的全流程并给出可直接复用的 C、Java、Python 三语言示例代码。读者学完后将能够在硬币检测、虹膜定位、医疗影像圆形目标识别等场景中独立完成圆的检测与可视化同时理解各参数背后的实现机制做到知其然更知其所以然。目标Goal掌握 OpenCV 图像处理核心函数HoughCircles()使用霍夫圆变换在图像中检测圆形目标。原理概述Theory从霍夫直线变换到圆变换的参数空间扩展霍夫圆变换的工作方式与前一篇教程介绍的霍夫直线变换Hough Line Transform大致类似但参数维度更高在直线检测中一条直线由两个参数 \((r, \theta)\) 定义在圆检测中一个圆需要三个参数才能唯一确定\[C : (x_{center}, y_{center}, r)\]其中 \((x_{center}, y_{center})\) 表示圆心位置\(r\) 表示半径。三者共同将圆完全定义如果直接对三维参数空间做标准霍夫累积计算量将非常庞大。因此OpenCV 并没有实现标准的三维霍夫变换而是采用了一种更高效的改进算法——霍夫梯度法Hough Gradient Method检测过程分为两个主要阶段第一阶段边缘检测并寻找可能的圆心。算法先对图像做 Canny 边缘检测对每一个非零点利用 Sobel 算子计算局部梯度方向并沿梯度方向以及反方向对累加器投票票数超过阈值的点即被认为是候选圆心第二阶段为每个候选圆心确定最佳半径。统计所有边缘点到候选圆心的距离出现频次最高累积最集中的距离即为该圆的最佳半径。更深入的数学细节可参考Learning OpenCV等计算机视觉经典书目。从本仓库源码结构看上述两阶段逻辑集中于 hough.cpp 中HoughCircles()的实现其中内部依次调用 Canny 边缘检测、梯度计算与圆心累加器投票等步骤。该示例程序完成哪些工作加载图像并做模糊降噪抑制噪声干扰对降噪后的图像应用霍夫圆变换在窗口中显示检测到的圆。代码准备示例文件与测试图像教程配套的完整示例代码位于仓库中可按需查看与运行Csamples/cpp/tutorial_code/ImgTrans/houghcircles.cppJavasamples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.javaPythonsamples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py测试图片为彩虹糖smarties实拍图 samples/data/smarties.png。运行时不传图片参数则默认加载该图Pythonpython3 hough_circle.py [image_name]C编译生成houghcircles可执行文件后运行./houghcircles [image_name]Java编译后运行HoughCircles主类默认读取相对路径下的data/smarties.png。分步实现讲解Explanation下面按处理流水线逐步说明各代码段的职责。三种语言代码结构一一对应可交叉对照。第一步加载图像//![load] const char* filename argc 2 ? argv[1] : smarties.png; Mat src imread( samples::findFile( filename ), IMREAD_COLOR ); if(src.empty()){ printf( Error opening image\n); printf( Program Arguments: [image_name -- default %s] \n, filename); return EXIT_FAILURE; } //![load]## [load] default_file smarties.png filename argv[0] if len(argv) 0 else default_file src cv.imread(cv.samples.findFile(filename), cv.IMREAD_COLOR) if src is None: print (Error opening image!) print (Usage: hough_circle.py [image_name -- default default_file ] \n) return -1 ## [load]//! [load] String default_file ../../../../data/smarties.png; String filename ((args.length 0) ? args[0] : default_file); Mat src Imgcodecs.imread(filename, Imgcodecs.IMREAD_COLOR); if( src.empty() ) { System.out.println(Error opening image!); System.exit(-1); } //! [load]要点按彩色图加载IMREAD_COLOR加载后务必检查图像是否为空避免空指针或内存错误。第二步转换为灰度图HoughCircles()要求输入为单通道 8 位灰度图因此先做色彩空间转换//![convert_to_gray] Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY); //![convert_to_gray]## [convert_to_gray] gray cv.cvtColor(src, cv.COLOR_BGR2GRAY) ## [convert_to_gray]//! [convert_to_gray] Mat gray new Mat(); Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY); //! [convert_to_gray]第三步中值滤波降噪避免虚假圆检测噪声会产生大量虚假边缘点直接干扰圆心投票。这里使用 5×5 的中值滤波medianBlur平滑灰度图//![reduce_noise] medianBlur(gray, gray, 5); //![reduce_noise]## [reduce_noise] gray cv.medianBlur(gray, 5) ## [reduce_noise]//![reduce_noise] Imgproc.medianBlur(gray, gray, 5); //![reduce_noise]要点中值滤波在去除椒盐类噪点的同时能较好保持边缘是霍夫圆检测前常用的预处理手段。输入图像本身较平滑时也可酌情省略或换用高斯模糊。事实上OpenCV 官方头文件也提示图像若非足够平滑先做高斯模糊如 7×7 核、sigma 1.5同样有助于提升检测稳定性。第四步调用 HoughCircles 执行圆检测核心检测调用如下C 示例代码//![houghcircles] vectorVec3f circles; HoughCircles(gray, circles, HOUGH_GRADIENT, 1, gray.rows/16, // 修改此值以适配圆心间距不同的场景 100, 30, 1, 30 // 修改最后两个参数 (min_radius max_radius) 以检测更大的圆 ); //![houghcircles]## [houghcircles] rows gray.shape[0] circles cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, rows / 8, param1100, param230, minRadius1, maxRadius30) ## [houghcircles]//! [houghcircles] Mat circles new Mat(); Imgproc.HoughCircles(gray, circles, Imgproc.HOUGH_GRADIENT, 1.0, (double)gray.rows()/16, // 修改此值以适配圆心间距不同的场景 100.0, 30.0, 1, 30); // 修改最后两个参数 (min_radius max_radius) 以检测更大的圆 //! [houghcircles]参数详解每个参数控制什么结合示例代码与 imgproc.hpp 中的官方函数声明与注释HoughCircles()的完整签名为void HoughCircles( InputArray image, OutputArray circles, int method, double dp, double minDist, double param1 100, double param2 100, int minRadius 0, int maxRadius 0 );各参数含义与取值建议汇总如下参数教程示例取值含义与调参要点gray—输入图须为8 位单通道灰度图circles输出容器输出向量每个检测结果被编码为 3 或 4 个浮点数 \((x, y, radius)\) 或 \((x, y, radius, votes)\)分别代表圆心横纵坐标、半径与可选累加器票数methodHOUGH_GRADIENT检测方法见HoughModes枚举。当前可用HOUGH_GRADIENT与HOUGH_GRADIENT_ALT两种详见下节教程中标注为当时唯一可用方法dp1累加器分辨率与图像分辨率的反比。dp1时累加器与输入图同分辨率dp2时累加器宽高各减半速度更快但定位精度下降。若使用HOUGH_GRADIENT_ALT官方推荐dp1.5除非需要检测很小的圆minDistgray.rows/16C/Java、rows/8Python 示例检测到的圆心之间的最小距离。过小会导致真正圆的周围被误检出多个邻近假圆过大则会漏掉部分圆。示例注释提示需按场景中圆与圆的间距动态调整param1C/Java 示例100方法相关参数一。对HOUGH_GRADIENT而言它是传给内部 Canny 边缘检测器的高阈值低阈值自动取它的一半。注意HOUGH_GRADIENT_ALT使用 Scharr 算子计算梯度阈值需相应调高如 300 左右param2C/Java 示例30方法相关参数二。对HOUGH_GRADIENT而言它是圆心检测阶段的累加器阈值越小越容易检出越多假圆且累加值大的圆会优先返回。对HOUGH_GRADIENT_ALT则是圆的完美度度量越接近 1 越苛刻通常 0.9 即可需检测小圆时可降到 0.85 甚至更低minRadius示例1教程说明文中写默认0检测的最小半径。若未知填 0 表示不设下限maxRadius示例30教程说明文中写默认0检测的最大半径。若 0则取图像最大边长若 0HOUGH_GRADIENT将只输出圆心而不计算半径HOUGH_GRADIENT_ALT始终会计算半径。示例注释提示需检测更大圆时调大这两个值说明教程说明文字段与配套示例代码中参数值略有出入说明文给出param1200、param2100*、半径 0而示例代码实际使用param1100、param230、minRadius1、maxRadius30实际运行时以示例代码为准二者都是针对smarties.png的有效配置实践中应按自己图像重新标定。第五步绘制检测结果检测到的圆用红色绘制轮廓、用绿色小点标记圆心BGR 颜色下分别以Scalar(255,0,255)品红与Scalar(0,100,100)表示//![draw] for( size_t i 0; i circles.size(); i ) { Vec3i c circles[i]; Point center Point(c[0], c[1]); // 绘制圆心 circle( src, center, 1, Scalar(0,100,100), 3, LINE_AA); // 绘制圆轮廓 int radius c[2]; circle( src, center, radius, Scalar(255,0,255), 3, LINE_AA); } //![draw]## [draw] if circles is not None: circles np.uint16(np.around(circles)) for i in circles[0, :]: center (i[0], i[1]) # 绘制圆心 cv.circle(src, center, 1, (0, 100, 100), 3) # 绘制圆轮廓 radius i[2] cv.circle(src, center, radius, (255, 0, 255), 3) ## [draw]//! [draw] for (int x 0; x circles.cols(); x) { double[] c circles.get(0, x); Point center new Point(Math.round(c[0]), Math.round(c[1])); // 绘制圆心 Imgproc.circle(src, center, 1, new Scalar(0,100,100), 3, 8, 0 ); // 绘制圆轮廓 int radius (int) Math.round(c[2]); Imgproc.circle(src, center, radius, new Scalar(255,0,255), 3, 8, 0 ); } //! [draw]要点HoughCircles输出的半径是浮点数绘制前先取整。圆心处用半径1、线宽3的小实心圆标示肉眼更醒目。第六步显示结果并等待用户按键退出//![display] imshow(detected circles, src); waitKey(); //![display]## [display] cv.imshow(detected circles, src) cv.waitKey(0) ## [display]//! [display] HighGui.imshow(detected circles, src); HighGui.waitKey(); //! [display]源码级原理补充读懂实现细节从函数声明看默认行为HoughCircles()在 imgproc.hpp 中声明param1、param2、minRadius、maxRadius均有默认值100 / 100 / 0 / 0这解释了教程未知半径时填 0的说法。输出向量支持 4 元素格式(x, y, radius, votes)其中第 4 个值携带累加器票数信息可在二次筛选时按投票强度过滤低置信度圆。两种方法模式HOUGH_GRADIENT 与 HOUGH_GRADIENT_ALT当前仓库头文件显示HoughModes枚举中可用方法已不止HOUGH_GRADIENT还包括HOUGH_GRADIENT_ALTHOUGH_GRADIENT经典霍夫梯度法即本教程主体由 Canny 边缘 Sobel 梯度方向投票实现HOUGH_GRADIENT_ALT精度更高的变体使用Scharr 算子计算导数边缘梯度更精确适合复杂背景下的圆检测但阈值param1需提高到约 300 量级dp建议取1.5param2按完美度解释越接近 1 要求圆越规整。具体实现边缘检测、梯度方向累加投票、半径直方图统计位于 hough.cpp 的HoughCircles()相关代码路径中感兴趣可深入阅读其源码理解两阶段的精确衔接方式。预处理为何如此关键官方头文件对HoughCircles的注释强调输入图像应适度平滑除非它本身已经很柔和并举例说明 7×7 高斯核配合 1.5 sigma 的模糊通常有助于检测——这与示例中用medianBlur的目的完全一致边缘越干净圆心投票越集中param2越容易设定误检越少。运行结果Result使用smarties.png测试图运行上述代码后彩虹糖颗粒被逐一检出检测窗口如下从结果可以看到每一颗圆形糖果都被红色轮廓标出、圆心处以绿点强调与预设参数minRadius1、maxRadius30吻合。调参实战建议小结从大到小调minDist先保证相近圆不被吞并再根据实际间距收紧param1决定边缘敏感度边缘碎、纹理多时适当提高避免把纹理当圆param2决定容错度圆不完整、光照不均时可下调以召回更多候选假圆增多时上调或配合minRadius/maxRadius缩小搜索范围善用minRadius/maxRadius已知目标尺寸量级时收紧该区间能显著抑制虚假圆并提升速度。至此你已经掌握了霍夫圆变换的理论脉络、HoughCircles()的完整调用链与每种语言的等价实现可以将其直接迁移到自己的圆形检测任务中。【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价