前面已经做了图片清晰度检测、图像差异检测、主色提取、自动纠偏、Canny 边缘检测和轮廓检测,这次继续做一个同样比较轻量的 OpenCV 小工具:
圆形检测。
有些场景里,我们不只是想知道图片中有没有边缘或者轮廓,而是想进一步判断:
图片里到底有几个圆?圆心在哪里?半径是多少?
所以这次我用华为云码道辅助开发了一个基于 OpenCV 的:
Hough Circle Detector
上传图片以后,程序会自动寻找圆形,并把检测结果直接绘制在原图上。
一、这个工具能做什么?
目前功能比较简单:
- 上传 JPG / PNG 图片
- 使用 OpenCV 自动检测圆
- 在图片中绘制检测圆
- 标出圆心
- 显示 Circle Count
- 显示每个圆的 Center X / Center Y
- 显示 Radius
- 支持设置 Min Radius / Max Radius
- 支持下载检测结果图
整体流程:
上传图片
↓
图像预处理
↓
HoughCircles
↓
检测圆心和半径
↓
绘制圆形
↓
显示检测结果
二、为什么检测圆不用 findContours?
上一篇轮廓检测中,我使用的是:
cv2.findContours()
它比较适合寻找:
闭合区域
物体轮廓
前景区域
但如果目标非常明确,就是:
寻找圆形
那 OpenCV 还有一个更加直接的方法:
cv2.HoughCircles()
它是基于霍夫变换思想专门寻找圆形结构的方法。
最终可以直接得到:
圆心 X
圆心 Y
半径 Radius
所以对于硬币、圆形按钮、圆孔等场景,会比单纯从轮廓里判断“像不像圆”更直接。
三、HoughCircles 的基本流程
这次检测过程可以简单理解成:
原始图片
↓
灰度化
↓
Gaussian Blur
↓
Hough Circle Transform
↓
筛选圆形
↓
输出圆心和半径
其中 Gaussian Blur 主要用于减少图片中的一些细小噪声。
如果直接对复杂边缘进行圆检测,可能会产生很多错误结果。
先做适度平滑,可以让圆的主要边缘更加稳定。
四、这次准备了 5 个不同大小的圆
为了让结果更加直观,这次没有继续使用狗狗自然图片,而是专门准备了一张白色背景测试图。
图片中一共有五个不同大小的圆:
红色圆
蓝色圆
绿色圆
黄色圆
紫色圆
这种图片比较适合验证:
Circle Count
圆心位置
半径大小
是否正确。
五、一开始最大红圆还检测错了
第一次运行的时候,其实出现了一个小问题。
页面设置的最大半径范围只有:
Max Radius = 200 px
结果虽然显示:
Circle Count = 5
数量看起来是对的,
但是最大的红色圆没有贴着真实外边缘,而是在红圆内部错误检测出了一个更小的圆。
原因也比较直接:
真实红圆半径已经超过了 200 px。
但是我们限制了:
Max Radius ≤ 200
算法根本没有机会搜索真正的大圆,只能在允许的范围内寻找一个近似结果。
六、扩大半径范围以后正常了
后面把 Max Radius 上限扩大以后重新测试。
最终使用:
Min Radius:
10 px
Max Radius:
512 px
这次五个圆全部正确贴合。
最终页面显示:
Circle Count:5
图片尺寸:
1536 × 1024
说明程序已经正确找到了测试图片中的五个圆。
七、五个圆的真实检测结果
页面还会输出每个圆的详细数据。
这次检测结果为:
| 编号 | Center X | Center Y | Radius |
|---|---|---|---|
| Circle 1 | 358 | 328 | 248 px |
| Circle 2 | 627 | 767 | 197 px |
| Circle 3 | 883 | 341 | 174 px |
| Circle 4 | 1201 | 764 | 145 px |
| Circle 5 | 1322 | 349 | 107 px |
可以看到:
五个圆的半径从:
248 px
↓
197 px
↓
174 px
↓
145 px
↓
107 px
逐渐变小。
这和测试图中实际看到的大小关系也是一致的。
八、为什么需要 Min Radius 和 Max Radius?
这两个参数其实很重要。
如果完全不限制圆的大小,算法可能会在一些:
小纹理
局部边缘
噪声区域
里误检测出很多圆。
所以可以提前告诉程序:
“我只关心这个尺寸范围内的圆。”
例如:
Min Radius = 10
表示小于 10 px 的圆不需要考虑。
Max Radius = 512
表示最大只需要寻找半径 512 px 以内的圆。
这样既能减少无意义搜索,也能降低错误检测概率。
九、这次的 bug 其实也挺典型
这次最大的红圆检测不准,并不是 HoughCircles 本身失效。
真正的问题是:
搜索参数限制错了。
一开始:
真实半径 > 200 px
但是:
Max Radius = 200 px
所以算法不可能返回正确的大圆。
扩大到:
512 px
以后,红圆就正常贴合了。
这个过程也说明,很多 OpenCV 算法效果不好时,不一定意味着算法不能用。
有时候真正需要检查的是:
输入图片
参数范围
预处理方式
而不是第一时间换算法。
十、圆心和半径有什么用?
HoughCircles 不只是告诉我们:
这里有一个圆。
它还会给出:
Center X
Center Y
Radius
所以后面可以继续进行很多处理。
例如:
计算圆面积
比较多个圆大小
统计圆的位置
判断圆之间距离
寻找最大圆
寻找指定区域内的圆
如果是工业视觉,还可以进一步用于:
圆孔检测
零件尺寸分析
圆形工件定位
十一、哪些场景比较适合 HoughCircles?
比较典型的应用包括:
硬币检测
圆形按钮检测
圆孔检测
圆形零件检测
仪表盘检测
圆形标志定位
只要目标本身具有比较明确的圆形边缘,就比较适合使用这种方法。
十二、它也不是目标检测
HoughCircles 本质上检测的是:
几何圆形结构。
它并不知道:
这是硬币
这是按钮
这是车轮
它只知道:
这里存在一个近似圆形。
所以它和 YOLO 这种语义目标检测还是完全不同的。
YOLO 关注的是:
“这是什么?”
HoughCircles 更关注:
“这里是不是一个圆?”
十三、为什么最近这些工具都比较简单?
最近我把文章节奏调整了一下。
不再每一篇都做一个很大的项目,而是:
一个小工具解决一个明确问题。
这次技术栈依旧很简单:
Python
OpenCV
FastAPI
原生 HTML / CSS / JavaScript
不需要模型训练,也不需要复杂依赖。
而且每一个项目都可以单独运行、单独截图、单独验证算法效果。
总结
这次用华为云码道辅助开发了一个:
OpenCV 霍夫圆检测工具。
核心流程:
图片上传
↓
灰度化
↓
Gaussian Blur
↓
HoughCircles
↓
检测圆心和半径
↓
绘制结果
真实测试中:
图片尺寸:
1536 × 1024
半径范围:
10–512 px
最终:
Circle Count = 5
检测到的半径分别为:
248 px
197 px
174 px
145 px
107 px
五个圆全部成功检测并绘制出来。
过程中还遇到了一个实际问题:
Max Radius 太小,导致最大红圆检测错误。
把范围从 200 px 扩大以后,结果恢复正常。
前面几篇分别解决了:
图片糊不糊?
两张图片哪里不一样?
图片主要是什么颜色?
图片歪了怎么办?
图片哪里有边缘?
图片有几个轮廓?
这一篇则回答:
图片里到底有几个圆?
下一篇可以继续换一个轻量方向:
图片有多亮?用华为云码道开发 OpenCV 亮度分析工具
上传图片以后直接计算:
平均亮度、最亮区域、最暗区域和亮度直方图。
这样就不用一直围绕“找形状”做,内容也会更丰富一点。