opencv-061-二值图像分析(霍夫圆检测)

知识点

根据极坐标,圆上任意一点的坐标可以表示为如下形式, 所以对于任意一个圆, 假设中心像素点p(x0, y0)像素点已知, 圆半径已知,则旋转360由极坐标方程可以得到每个点上得坐标同样,如果只是知道图像上像素点, 圆半径,旋转360°则中心点处的坐标值必定最强.这正是霍夫变换检测圆的数学原理。

API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
OpenCV中霍夫圆检测的API与参数解释如下:
void cv::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 表示检测的圆信息(圆心+半径)
method 圆检测的方法
dp表示图像分辨率是否有变化,默认1表示保持跟原图大小一致,一般取2,比1 要大
minDist表示检测到的圆,两个圆心之间的最小距离
param1 表示边缘提取的高阈值
param2表示霍夫空间的累加阈值
minRadius 表示可以检测圆的最小半径
maxRadius 表示可以检测圆的最大

代码(c++,python)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

/*
* 二值图像分析(霍夫圆检测)
*/
int main() {
Mat src = imread("../images/coins.jpg");
if (src.empty()) {
cout << "could not load image.." << endl;
}
imshow("input", src);

// 转换为灰度空间与高斯模糊
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
GaussianBlur(gray, gray, Size(9, 9), 2, 2);

// 霍夫圆检测
int dp = 2; // 在其它参数保持不变的情况下。dp的取值越高,越容易检测到圆
int min_radius = 20;
int max_radius = 100;
int minDist = 10;
vector<Vec3f> circles;
HoughCircles(gray, circles, HOUGH_GRADIENT, dp, minDist,
100, 100, min_radius, max_radius);
for (size_t i = 0; i < circles.size(); ++i) {
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// 绘制圆
circle(src, center, radius, Scalar(0, 0, 255), 3);
circle(src, center, 3, Scalar(0, 255, 0), -1); //绘制圆心
}

imshow("result_dp=2", src);

waitKey(0);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import cv2 as cv
import numpy as np


src = cv.imread("D:/images/test_coins.png")
cv.namedWindow("input", cv.WINDOW_AUTOSIZE)
cv.imshow("input", src)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
gray = cv.GaussianBlur(gray, (9, 9), 2, 2)
dp = 2
param1 = 100
param2 = 80


circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, dp, 10, None, param1, param2, 20, 100)
for c in circles[0,:]:
print(c)
cx, cy, r = c
cv.circle(src, (cx, cy), 2, (0, 255, 0), 2, 8, 0)
cv.circle(src, (cx, cy), r, (0, 0, 255), 2, 8, 0)


cv.imshow("hough line demo", src)
cv.waitKey(0)
cv.destroyAllWindows()

结果

代码地址

github