霍夫圆检测
笛卡尔坐标系中,圆的方程为(x-a)^2+(y-b)^2=r^2
其中(a,b)是圆心,r是半径
也可以表示为
x=a+rcosθ
y=b+rsinθ
再进行一次转换
a=x-rcosθ
b=y-rsinθ
此时由于xy是给定的,将abr看成变量,映射到abr的三维坐标系中如图
所有经过(x,y)点的圆都可以用这条曲线表示
同样,在xy坐标系中的所有圆都可以在这个三维坐标系中用曲线表示出来
假设空间中有三个点ABC,经过ABC三点的圆都是无数多的,在abr坐标系中可以可以表示为三条曲线,但是如果有一个圆同时过ABC三点,那么在abr坐标系中,它对应三条曲线的交点
因此,在xy坐标系中的一个圆上的所有点的圆方程,他们在abr坐标系中会交于同一点,通过判断abr坐标系中该点有多少条直线相交,大于一定阈值的点就认定为圆
代码演示
#include"pch.h" #include<iostream> #include<opencv2/opencv.hpp> using namespace std; using namespace cv; int main(int argc, char **argv) { Mat src, dst; src = imread("2.jpg"); if (!src.data) { printf("Error\n"); return -1; } char INPUT_TITLE[] = "input_image"; char OUTPUT_TITLE[] = "hough_circle_demo"; namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE); namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE); imshow(INPUT_TITLE, src); //中值滤波 Mat mlf_opt; medianBlur(src, mlf_opt, 3);//ksize取3 cvtColor(mlf_opt, mlf_opt, CV_BGR2GRAY); //霍夫圆检测 vector<Vec3f> pcircles;//可能的圆心 HoughCircles(mlf_opt, pcircles, CV_HOUGH_GRADIENT, 1, 10, 100, 35, 5, 50); cout << pcircles[1] << endl; src.copyTo(dst); for (size_t i = 0; i < pcircles.size(); ++i) { Vec3f cc = pcircles[i]; circle(dst, Point(cc[0], cc[1]), cc[2], Scalar(0, 0, 255), 2, LINE_AA); circle(dst, Point(cc[0], cc[1]), 1, Scalar(198, 20, 255), 2, LINE_AA); } imshow(OUTPUT_TITLE, dst); waitKey(0); return 0; }
函数带有以下自变量:
- src_gray: 输入图像 (灰度图)
- circles: 存储下面三个参数: 集合的容器来表示每个检测到的圆.
- CV_HOUGH_GRADIENT: 指定检测方法. 现在OpenCV中只有霍夫梯度法
- dp = 1: 累加器图像的反比分辨率
- min_dist = src_gray.rows/10: 检测到圆心之间的最小距离
- param_1 = 100: Canny边缘函数的高阈值
- param_2 = 35: 圆心检测阈值.
- min_radius = 5: 能检测到的最小圆半径, 默认为0.
- max_radius = 50: 能检测到的最大圆半径, 默认为0
circle打印圆,第一个打印边界,第二个打印圆心(半径调小)
无情的摸鱼机器