OpenCV中的霍夫圆变换
在图像处理与计算机视觉中,圆形检测是一项常见的任务,应用场景包括车牌识别、瞳孔检测、交通标志识别等。霍夫圆变换(Hough Circle Transform)是一种高效且鲁棒的算法,通过在参数空间中寻找局部极大值,能够在存在噪声和部分遮挡的情况下检测出图像中的圆形。
本文将从基本理论、参数空间构造、算法实现步骤、以及 OpenCV C++ 中的代码示例几方面详细介绍霍夫圆变换也算为上一篇:霍夫直线检测的内容补充。
1. 霍夫圆变换简介
1.1 基本概念
传统的圆可以用中心坐标 ( a , b ) (a,b) (a,b) 和半径 r r r表示,其标准方程为:
( x − a ) 2 + ( y − b ) 2 = r 2 (x-a)^2+(y-b)^2=r^2 (x−a)2+(y−b)2=r2
在图像中,圆上的每个边缘点都满足上述方程。因此,霍夫圆变换的核心思想是:
- 边缘点投票:利用检测到的边缘点,将每个点对所有可能的圆参数 ( a , b , r ) (a,b,r) (a,b,r)进行“投票”。
- 参数累加器:在三维参数空间上(或采用分阶段处理,将半径单独处理)构建累加器,对满足圆方程的参数组合进行计数。
- 寻找峰值:当累加器中某个区域的投票数超过预设阈值时,就可以认为参数对应的圆存在于图像中。
这种方法相较于遍历图像上所有可能的圆,具有更高的效率和鲁棒性。
1.2 参数空间的构造
参数方程:
x = a + r c o s ( θ ) ; y = b + r s i n ( θ ) x=a+rcos(\theta);y=b+rsin(\theta) x=a+rcos(θ);y=b+rsin(θ)
换种写法:
a = x − r c o s ( θ ) ; b = y − r s i n ( θ ) a=x-rcos(\theta);b=y-rsin(\theta) a=x−rcos(θ);b=y−rsin(θ)
对于圆形检测,其参数空间为三维空间 ( a , b , r ) (a,b,r) (a,b,r),所以在abr组成的三维坐标系中,一个点可以确定一个圆。在xy坐标系中同一个圆上的所有点的圆方程式一样的,它们转到参数方程abr坐标系中为同一个点。所以在abr坐标系中,圆上的所有像素点应该相交。通过累计相交数量确定圆。如下图:
在实际实现中,由于直接使用三维累加器计算量较大,为了加速处理通常会进行如下处理:
- 预先边缘检测:例如使用 Canny 算子,降低噪声干扰。
- 使用梯度信息:利用边缘点的梯度方向,有助于估计圆心位置,从而减少参数空间的搜索范围。
- 多尺度搜索:根据期望目标的大小范围,对半径 r 进行分层处理或限定搜索范围。
2. 算法实现步骤
霍夫圆变换的基本流程可概括为以下步骤:
- 预处理
- 灰度转换:将彩色图像转为灰度图。
- 平滑滤波:使用高斯模糊减少图像噪声,以提高边缘检测效果。
- 边缘检测
- 利用 Canny 算子提取图像中的边缘信息,从而获得候选的圆上点。
- 梯度和投票
- 对于每个边缘点,根据梯度方向估计可能的圆心位置。
- 在参数空间中对每个候选的 ( a , b , r ) (a,b,r) (a,b,r)位置进行累加投票。
- 累加器峰值检测
- 统计累加器中每个参数组合的票数,找出局部最大值区域,认为这些区域对应图像中的圆。
- 结果输出
- 将检测到的圆的参数进行输出,并在图像中绘制出圆心和圆边。
3. OpenCV 中的实现:HoughCircles
OpenCV 封装了上述原理,通过函数 HoughCircles
直接进行圆形检测。下面我们介绍该函数的主要参数及使用方法。
3.1 函数原型及参数说明
cpp
复制编辑
void HoughCircles(InputArray image,OutputArray circles,int method,double dp,double minDist,double param1 = 100,double param2 = 100,int minRadius = 0,int maxRadius = 0
);
- image:输入图像,通常为经过灰度化与高斯模糊后的图像。
- circles:输出的圆信息,每个圆用三个值表示 ( x , y , r ) (x,y,r) (x,y,r),其中 ( x , y ) (x,y) (x,y) 为圆心坐标, r r r 为半径。
- method:检测方法,目前支持
HOUGH_GRADIENT
。 - dp:累加器分辨率与原始图像分辨率的反比(例如,设 dp=1 表示累加器与图像同一分辨率)。
- minDist:检测到的圆之间的最小距离,防止检测到重复圆。
- param1:用于 Canny 边缘检测的高阈值(低阈值一般为其一半)。
- param2:累加器阈值,值越小,检测到的圆越多,但可能伴随误检。
- minRadius 和 maxRadius:待检测圆的半径最大最小范围,用于限制搜索空间。
4. OpenCV C++ 示例代码
下面是一段使用 HoughCircles
进行圆形检测的完整示例代码,帮助你快速上手使用霍夫圆变换:
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main()
{// 1. 读取图像并预处理Mat src = imread("E:/image/coin.png");if (src.empty()){cout << "无法加载图像!" << endl;return -1;}// 转换为灰度图Mat gray;cvtColor(src, gray, COLOR_BGR2GRAY);Mat cannyDst;// 使用Canny边缘检测// 使用高斯模糊以减少噪声GaussianBlur(gray, gray, Size(9, 9), 2, 2);Canny(gray, cannyDst, 100, 150);imshow("gray",gray);// 2. 使用霍夫圆变换检测圆形vector<Vec3f> circles;HoughCircles(gray, circles, HOUGH_GRADIENT,1, // dp: 累加器分辨率60, // minDist: 圆心之间的最小距离150, // param1: Canny高阈值95, // param2: 累加器阈值(阈值越低检测越多圆)3, // minRadius: 最小圆半径0); // maxRadius: 最大圆半径// 3. 绘制检测到的圆Mat result = src.clone();for (size_t i = 0; i < circles.size(); i++){// circles[i] 为 (x, y, r)Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));int radius = cvRound(circles[i][2]);// 绘制圆心(小圆)circle(result, center, 3, Scalar(0, 255, 0), -1);// 绘制圆的边缘circle(result, center, radius, Scalar(0, 0, 255), 2);}// 显示结果imshow("canny", cannyDst);imshow("霍夫圆变换检测", result);waitKey(0);return 0;
}
代码说明:
- 预处理阶段中,图像先经过灰度转换再使用高斯模糊,有助于减少噪声影响。
- 调用
HoughCircles
时传入合适的参数,其中dp
设置为 1 表示累加器与输入图像分辨率相同;minDist
用于避免多个圆心过于接近。 - 检测到的圆信息存储在
circles
中,然后依次绘制圆心和圆轮廓。
上面还有一个没用检测出来,可以通过调整参数进行优化
5. 参数调优与注意事项
在使用霍夫圆变换时,参数选择对检测结果影响较大,可参照以下建议进行调节:
- 图像预处理
- 高斯模糊有助于消除噪点,但模糊参数不宜过大,以免模糊掉边缘信息。
- Canny 边缘检测参数
param1
控制边缘检测阈值,适当提高可减少噪声,但可能漏掉较弱的边缘。
- 累加器阈值
param2
决定累计票数的阈值,调低会检测到更多圆,但同时可能出现误检。
- 半径范围
- 根据实际需求合理设置
minRadius
与maxRadius
能有效缩小搜索空间,提高准确性。
- 根据实际需求合理设置
6. 总结
霍夫圆变换利用边缘点在参数空间内的投票机制,实现了对图像中圆形的鲁棒检测。通过:
- 灰度化与高斯模糊进行预处理,
- 使用 Canny 算子提取边缘,
- 在 ( a , b , r ) (a,b,r) (a,b,r)参数空间中统计累加器,
- 提取局部峰值确定圆的参数,
我们可以在 OpenCV 中借助 HoughCircles
简单实现这一算法。掌握了参数调优和原理后,可以在各种应用场景中自如地检测出目标圆形,提高图像处理效果。