一、基本原理
opencv中圆识别的基本原理如下:
1、canny算子求图像的单像素二值化边缘
2、假设我们需要找半径为R的所有圆,则对于边缘图中的每一个边缘点,该边缘点的切线的法线方向上(正负两个方向),寻找到该边缘点距离为R的点,将该点的计数加1(初始化所有点的计数都是0)
3、找到计数值大于门限值的点,即圆心所在的点
二、代码分析
代码在/modules\imgproc\src\hough.cpp文件icvHoughCirclesGradient函数中
static void
icvHoughCirclesGradient( CvMat* img, float dp, float min_dist,
int min_radius, int max_radius,
int canny_threshold, int acc_threshold,
CvSeq* circles, int circles_max )
{
//参数:
//img: 输入图像
//dp: 识别精度,1.0表示按照原图精度
//min_dist: 圆心点位置识别精度
//min_radius: 所需要找的圆的最小半径
//max_radius:所需要找的圆的最大半径
//canny_threshold:canny算子的高阀值
//acc_threshold:累加器阀值,计数大于改阀值的点即被认为是可能的圆心
//circles: 保存找到的符合条件的所有圆
//circles_max: 最多需要的找到的圆的个数
const int SHIFT = 10, ONE = 1 << SHIFT, R_THRESH = 30;
cv::Ptr<CvMat> dx, dy;
cv::Ptr<CvMat> edges, accum, dist_buf;
std::vector<int> sort_buf;
cv::Ptr<CvMemStorage> storage;
int x, y, i, j, k, center_count, nz_count;
float min_radius2 = (float)min_radius*min_radius;
float max_radius2 = (float)max_radius*max_radius;
int rows, cols, arows, acols;
int astep, *adata;
float* ddata;
CvSeq *nz, *centers;
float idp, dr;
CvSeqReader reader;
//canny算子求单像素二值化边缘,保存在edges变量中
edges = cvCreateMat( img->rows, img->cols, CV_8UC1 );
cvCanny( img, edges, MAX(canny_thresh