Hough变换检测圆
我们在之前利用Hough变换实现了直线的检测,因为两个特征(k,b)或者(theta,r)就能确定一条直线,所以我们的Hough空间是二维的。一个圆由3个特征组成,分别是圆心的横坐标,纵坐标,以及圆的半径,因此我们的Hough空间是三维的。
圆的方程:(x-a)^2 + (y-b)^2 = r^2
过一点(x0,y0),a,b,r的关系就是:(x0-a)^2 + (y0-b)^2 = r^2
因此,我们的Hough空间[a是横坐标,b是纵坐标,r是竖坐标]
我们要用一个二重循环去填充Hough空间
跟直线检测一样,我们现在是在三维数组里找局部最大值,确定圆的(x,y,r)
听完之后是不是觉得方法很简单,跟检测直线没什么区别,也用不到极坐标。
但是,三维累加器中会产生许多噪声并且使得结果不稳定的稀疏分布!
因此,由Hough梯度法来改进这个算法。
Hough梯度法
- 利用canny检测提取边缘
- 对每一个边缘点,我们可以计算出梯度[其实就是圆心和边缘点连线方向]
- 计算出梯度后,我们就可以得到一条垂直于该点切线的直线,我们就有一个二维数组H,用来填充这条直线上所有点
- H中出现频率最高的肯定就是圆心
- 对于得到的圆心中的每一个,计算那些边缘点到该圆心的距离,若某个距离很充分出现次数足够,就可以认为这是一个合格的圆
//Hough变换检测圆
#include "cv.h"
#include "highgui.h"
#include "math.h"
int main(int argc, char** argv) {
IplImage* img = cvLoadImage("corner.tif", );
IplImage* gray = cvCreateImage(cvGetSize(img), , );
CvMemStorage* storage = cvCreateMemStorage();
cvCvtColor(img, gray, CV_BGR2GRAY);
cvSmooth(gray, gray, CV_GAUSSIAN, , );
//cvHoughCircles(image,storage,method,dp,min_dist,p1 = 100,p2 = 100,min_radius = 0,max_radius = 0);
//CV_HOUGH_GRADIENT H.K于2003年发表的21HT方法
//dp检测圆心累加器的分辨率,1不变,2累加器尺寸为原图一半
//min_dist 检测到的圆心之间的最小距离。取值太小,在一个圆被分解为多个圆。太大则漏检
//p1在CV_HOUGH_GRADIENT情况下,此参数为传递给Canny边缘检测算子的两个阈值较高的那个,低阈值为其一半
//p2取值越小则误检很多不存在的圆
//mix_radius 被搜索圆得最小半径,小于此半径被忽略
//max_radius 最大半径,默认为max(width,height);
CvSeq* circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, , gray->height / , , );
int i;
for (i = ; i < circles->total; i++) {
float* p = (float*)cvGetSeqElem(circles, i);
cvCircle(img, cvPoint(cvRound(p[]), cvRound(p[])), , CV_RGB(, , ), -, , );
cvCircle(img, cvPoint(cvRound(p[]), cvRound(p[])), cvRound(p[]), CV_RGB(, , ), , , );
}
cvNamedWindow("circles", );
cvShowImage("circles", img);
cvWaitKey();
return ;
}