1.概念
公式原理:
其中(a,b)为圆心坐标。
霍夫变换检测圆形的原理跟检测直线的原理是一样的。圆的表达式为 (x-a)^2+(y-b)^2=r^2 , 把问题转换成在求解经过像素点最多的 (a,b,r) 参数对。发现(a,b,r)的参数空间特别大,一般使用霍夫梯度法来解决圆的变换。
如果我们对一个圆求梯度,那么圆上所有的点的梯度的方向均朝向圆心
基于此有如下原理:
(1)首先对图像应用边缘检测,比如用canny边缘检测
(2)使用sobel算子计算所有像素的梯度
(3)遍历canny之后的所有非0的像素点,沿着梯度方向画线,每个点有是一个累加器,有一个线经过该点,累加器加1,对所有累加器进行排序,根据阈值找到所有可能的圆心
(4)计算canny图像中所有的非0像素点距离圆心的距离,距离从小到大排序,选取合适的半径
(5)对选取的半径设置累加器,对于满足半径r的累加器+1
(6)统计所有可能的半径
原理部分参考这位大佬解释的:https://blog.csdn.net/u013263891/article/details/82867251
2.API介绍
HoughCircles(InputArray image,OutputArray circles, Int method, Double dp, Double mindist, Double param1,Double param2, Int minradius, Int maxradius)
参数1 image:8位,单通道图像。
参数2 circles:输出圆的信息结果。
参数3 method:定义检测图像中圆的方法。目前唯一实现的方法是cv2.HOUGH_GRADIENT。
参数4 dp:累加器分辨率与图像分辨率的反比。dp获取越大,累加器数组越小。
参数5 minDist:检测到的圆的中心(x,y)坐标之间的最小距离。如果minDist太小,则可能导致检测到多个相邻的圆。如果minDist太大,则可能导致很多圆检测不到。
参数6 param1: canny edge detection low threshold
参数7 param2:cv2.HOUGH_GRADIENT方法的累加器阈值。阈值越小,检测到的圈子越多。
参数8 minRadius:最小半径。
参数9 maxRadius:最大半径。
3.代码实现
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace std;
using namespace cv;
char inputName[] = "input name";
char outputName[] = "output name";
int main()
{
Mat src, dst,srcGray;
src = imread("D:/VS project/Image/circle.jpg");
if (src.empty())
{
cout << "找不到图像" << endl;
return -1;
}
namedWindow(inputName, CV_WINDOW_AUTOSIZE);
imshow(inputName, src);
namedWindow(outputName, CV_WINDOW_AUTOSIZE);
//第一步中值滤波降噪
medianBlur(src, srcGray, 5);
cvtColor(srcGray, srcGray, COLOR_BGR2GRAY);
//第二步霍夫检测圆
vector<Vec3f> circles;
HoughCircles(srcGray, circles, HOUGH_GRADIENT, 1, 10, 100, 30, 5, 50);
//变回彩图
cvtColor(srcGray, dst, COLOR_GRAY2BGR);
Scalar color = Scalar(0, 0, 255);
for (size_t i = 0; i < circles.size(); i++)
{
Vec3f c = circles[i];
circle(dst, Point(c[0], c[1]), c[2], color, 5,LINE_AA);
}
imshow(outputName, dst);
waitKey(0);
return 0;
}