霍夫圆形变换
原理
霍夫圆形变换和霍夫直线变换的原理类似:
- 在霍夫直线变换中,笛卡尔坐标系中的直线被变换成了霍夫空间中的 ( r , θ ) (r, \theta) (r,θ)。
- 在霍夫圆形变换中,笛卡尔坐标系中的圆被变换乘霍夫空间中的 C : ( x c e n t e r , y c e n t e r , r ) C:(x_{center}, y_{center}, r) C:(xcenter,ycenter,r);其中 ( x c e n t e r , y c e n t e r ) (x_{center},y_{center}) (xcenter,ycenter)为圆心, r r r为圆的半径。
在OpenCV中,处于效率的考虑,使用的并不是标准霍夫变换,而是霍夫斜率方法(Hough gradient method),这个方法分为两个主要步骤:
- 边缘检测,并找出可能的圆心
- 为每个可能的圆心找到最合适的半径
API
OpenCV中霍夫圆形变换的方法为HoughCircles()
函数,其原型如下:
void cv::HoughCircles( InputArray image, //8为单通道灰度输入图
OutputArray circles, //圆形结果向量数组
int method, //检测方法
double dp, //霍夫空间中的最小单元与图片像素的比例的倒数
double minDist, //检测到的圆形的圆心之间的最小距离
double param1 = 100, //定义检测方法的辅助参数
double param2 = 100, //定义检测方法的辅助参数
int minRadius = 0, //圆形的最小半径
int maxRadius = 0) //圆形的最大半径
HoughCircles()
方法检测圆心的精确率比检测半径要高,所以如果用户知道图片中的圆的半径的范围,则最好在参数中指定这个范围。也可以将maxRadius
设置为负数,这样就只检测圆心,然后再用别的方法去确定半径。
实例
使用OpenCV的示例图:"...\opencv\sources\samples\data\smarties.png"
圆形检测的完整步骤:
- 灰度化+中值滤波,去除噪音
- 使用
HoughCircles()
函数进行圆形检测 - 绘制检测结果
完整代码如下:
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
using namespace std;
int main() {
Mat src{ imread("smarties.png") };
//灰度化
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
//中值滤波-去除噪音
medianBlur(gray, gray, 5);
//检测圆形
vector<Vec3f> circles;
HoughCircles(gray, circles, HOUGH_GRADIENT, 1,
gray.rows / 16, //圆心间的距离最小为图片高度的1/16
100, //Canny边缘检测的上阈值
30, //圆形检测的阈值
1, //最小半径
30); //最大半径
//绘制检测结果
Mat dst{ src.clone() };
for (size_t i{ 0 }; i < circles.size(); i++) {
Vec3i c{ circles[i] };
Point center{ Point(c[0], c[1]) };
//圆心
circle(dst, center, 1, Scalar(0, 100, 100), 3, LINE_AA);
//圆周
int radius{ c[2] };
circle(dst, center, radius, Scalar(255, 0, 255), 3, LINE_AA);
}
imshow("原图", src);
imshow("检测结果", dst);
waitKey(0);
}
运行效果如下(左图为原图,右图为检测结果):