前面几次的内容,包括基础知识介绍和综合训练,基本上都是围绕着霍夫变换检测直线来进行展开的。那么这次我要来探讨霍夫变换检测圆。话不多说,首先我们来简要地看看霍夫变换检测圆是什么原理。
霍夫变换检测圆的原理及其实现
前面的学习,让我对霍夫变换有了这样一种理解-----实际上就是坐标变换,是一种数学上的变换,然后再转换到参数坐标系进行讨论,最终确定待检测圆(或者其他形状)的数学方程,那么圆在直角坐标系中的数学表达式我相信小学生都知道:
R^2 = (X - a)^2 + (Y - b)^2
我们看到了这个式子是比较复杂的,我首先要明确目标,这个式子的参数有三个:R、a、b,我们实际上是要根据已知的X,Y来将上述未知的三个参数求出来,可想而知,我们要是用上面这个式子就麻烦了,三个参数在一个式子中混为一谈,所以,我们要找另外的数学表达式,这样我们自然而然想到一般要使用的坐标系---极坐标系,在极坐标系下,圆的数学表达式如下:
X0 = X + R * cos(Theta)
Y0 = Y + R * sin(Theta)
这样,三个参数就成功分离了两个X0、Y0,此处若我们给定检测的R,再利用Theta的有界性,我们就可以得到一组合适的X0,Y0,R,于是圆就找到了!
类似于霍夫变换直线检测,这里我们也定义一个累加器,但是与直线检测不同的是,直线检测参数是二维的,而圆的参数是三维的,于是,我们可以定义一个三维的累加器,实现代码(关键函数)如下:
//Hough变换检测圆的函数
IplImage* HoughForCircle(IplImage* img, int radius, int interval)
{
IplImage* gray = cvCreateImage(cvGetSize(img), 8, 1);
IplImage* result = cvCreateImage(cvGetSize(img), 8, 3);
cvCopy(img, result);
cvCvtColor(img, gray, CV_BGR2GRAY);
//定义并初始化累加器
int ***count;
count = new int**[radius];
for (int i = 0; i < radius; ++i)
{
count[i] = new int*[img->height];
}
for (int i = 0; i < radius; ++i)
{
for (int j = 0; j < img->width; ++j)
{
count[i][j] = new int[img->width];
}
}
for (int k = 0; k < radius; ++k)
{
for (int i = 0; i < img->height; i++)
{
for (int j = 0; j < img->width; j++)
{
count[k][i][j] = 0;
}
}
}
/*
已知半径,遍历角度,遍历图像像素,得到圆心坐标
*/
int x0 = 0, y0 = 0;
for (int k = 0; k < radius; ++k)
{
for (int i = 0; i < img->height; ++i)
{
for (int j = 0; j < img->width; ++j)
{
//判断是不是前景点,默认黑色为背景色,白色为前景色
CvScalar s = cvGet2D(img, i, j);
int data = s.val[0];//用该方法,牺牲时间,但是比较保险,不容易出错
if (data > 0)//是前景点
{
for (int theta = 0; theta < (1 / interval) * 360; theta++)
{
double t = ((1 / interval) * theta * CV_PI) / 180;
x0 = (int)cvRound(j - k * cos(t));
y0 = (int)cvRound(i - k * sin(t));
if (x0 < img->width && x0 > 0 && y0 < img->height && y0 > 0)
{
count[k][y0][x0] = count[k][y0][x0] + 1;
}
}
}
}
}
}
/*
寻找累加器中的最大值
*/
int max = 0;
int r = 0;
int x = 0, y = 0;
for (int k = 1; k < radius; ++k)
{
for (int i = 0; i < img->height; ++i)
{
for (int j = 0; j < img->width; ++j)
{
if (count[k][i][j] > max)
{
max = count[k][i][j];
x = j;
y = i;
r = k;
}
}
}
}
cout << x << endl;
cout << y << endl;
cout << r << endl;
CvPoint point;
point.x = x;
point.y = y;
//画圆
cvCircle(result, point, r, CV_RGB(0, 255, 0));
//释放三维数组
for (int i = 1; i < radius; ++i)
{
for (int j = 0; j < img->width; ++j)
{
delete [] count[i][j];
count[i][j] = NULL;
}
}
for (int i = 1; i < radius; ++i)
{
delete[] count[i];
count[i] = NULL;
}
delete[] count;
count = NULL;
return result;
}
检测结果如下:
这里要注意几点:1.上述只是我自己写的一个简单的例子,细心的读者会发现,这里只检测了累加器的最大值,也就是只检测了一个圆,这显然是不合理的。但是,要想改进也非常容易,可以规定检测几个圆或者通过最大值制定阈值···实现起来也就是稍微改进一下,并不复杂;
2.这里new了一个三维数组,那么一定要记得delete,否则会造成内存泄露,前面几次我都忽视了这个问题,这是不对的。
霍夫变换检测圆openCV实现
openCV提供了Hough变换检测圆的函数:
CvSeq* cvHoughCircles (
CvArr* image,
void circle_storage,
int method,
double dp,
double min_dist,
double param1 = 100,
double param2 = 300,
int min_radius = 0,
int max_radius = 0
);
输入参数解释如下:
image:当然是输入图像,这里和霍夫变换直线检测不一样的是,霍夫变换检测圆的输入图像允许是8位图像,而检测直线是需要输入二值图像;
circle_storage:这里类似于HoughLines2,既可以是数组也可以是内存的存储器,这取决于我们希望返回什么结果;
method:检测方法,这里只能是CV_HOUGH_GRADIENT
dp:指累加器图像的分辨率,必须要大于等于1。这个参数实际上允许创建一个比输入图像分辨率低的累加器;
min_dist:区分两个不同圆之间的最小距离
param1:canny算法的高阈值,低阈值设为其的一半
param2:累加器的阈值
使用代码参考如下:
IplImage* img = cvLoadImage("5.png");
IplImage* dst = cvCreateImage(cvGetSize(img), 8, 1);
cvCvtColor(img, dst, CV_RGB2GRAY);
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* result = cvHoughCircles(dst, storage, CV_HOUGH_GRADIENT, 1, 10, 100, 36);
for (int i = 0; i < result->total; ++i)
{
float* p = (float*)cvGetSeqElem(result, i);
CvPoint point = cvPoint(cvRound(p[0]), cvRound(p[1]));
cvCircle(img, point, cvRound(p[2]), CV_RGB(0, 255, 0));
}
cvNamedWindow("dst");
cvShowImage("dst", img);
cvWaitKey(0);
cvDestroyAllWindows();
cvReleaseImage(&img);
cvReleaseImage(&dst);
实验结果:
惊奇的发现,openCV自带的函数居然检测效果还没有自己写的要好,这也说明了openCV的函数不是万能的。简单的了解下,我知道了openCV的函数使用了比较巧妙的方法,利用圆心必在经过圆上一点的切线的垂线方向这一定理,避免了x-y-r三维寻找圆速度慢的弊端。具体的实现方法(个人有没有想明白的地方,需要进一步想清楚再做实现):
1.首先确定前景点,即用canny算法边缘化,有必要的话要使用到图像细化
2.要找到每一个前景点切线的垂线方向,实际上就是找这个前景点的梯度方向,而这个梯度方向配合该前景点坐标可以确定该点切线的垂线方向的直线方程,通过这个直线方程遍历图像,是累加器加1
3.候选点必须大于给定阈值并且是近邻的局部最大值
4.比较累加器,将每个元素按降序排列,方便得出最有可能得中心
5.(不太明白)如何找半径
·······
虽然有不太明白的地方,但是,已经可以看出比上文中自写的程序思路要巧妙多了,这很好地解决了事先不知道圆半径的问题
(未完待续)
相关推荐
【OpenCV入门教程之十四】主要讲解了OpenCV中的霍夫变换,包括霍夫线变换和霍夫圆变换。霍夫变换是一种图像处理中的特征提取技术,由Paul Hough在1962年提出,主要用于从黑白图像中检测直线和曲线。它的基本思想是在...
例如,Canny边缘检测算法用于找出图像中的边界,霍夫变换用于检测直线和圆等几何形状,SIFT和SURF等特征检测器则在物体识别和匹配中起到关键作用。 配合C++源码的学习,你可以更直观地理解这些概念的实现过程。每一...
同时,也会涉及模板匹配和霍夫变换等图像检测方法。 在进阶部分,读者将接触到更复杂的话题,如物体检测和识别。OpenCV3提供了多种物体检测模型,如Haar级联分类器和HOG+SVM,书中会详细解释如何训练这些模型并应用...
该模块提供了丰富的图像处理功能,例如图像金字塔、基本的阈值操作、线性滤波器、Canny边缘检测、霍夫变换以及图像仿射变换等。这些操作和变换对于图像特征提取、图像分割、图像校正等高级计算机视觉任务至关重要。 ...
博文《【OpenCV入门教程之十四】OpenCV霍夫变换:霍夫线变换,霍夫圆变换合辑》的配套详细注释源代码。 博文链接: http://blog.csdn.net/poem_qianmo/article/details/26977557 1.已将dll打包到Release文件夹下...
OpenCvSharp 是一个OpenCV的.Net wrapper,应用最新的OpenCV库开发,使用习惯比EmguCV更接近原始的OpenCV,有详细的使用样例供参考。该库采用LGPL发行,对商业应用友好。使用OpenCvSharp,可用C#,VB.NET等语言实现...
基于C++和Opencv编写的直线霍夫变换底层源码+sln解决方案.zip基于C++和Opencv编写的直线霍夫变换底层源码+sln解决方案.zip基于C++和Opencv编写的直线霍夫变换底层源码+sln解决方案.zip基于C++和Opencv编写的直线霍夫...
OpenCV-Python不仅限于基本操作,还可以实现复杂的功能,比如图像的边缘检测、轮廓查找、霍夫变换等。对于初学者,建议从官方文档和在线教程开始学习,逐步掌握OpenCV的基本用法和高级特性。 通过不断实践和深入...
更复杂的示例可能涉及到特征检测,如SIFT或SURF,或者是使用霍夫变换检测直线或圆。 在学习过程中,你需要掌握的关键点包括: 1. 图像处理基础:了解像素、色彩空间、直方图均衡化等概念。 2. 边缘检测:Canny、...
OpenCvSharp 是一个OpenCV的.Net wrapper,应用最新的OpenCV库开发,使用习惯比EmguCV更接近原始的OpenCV,有详细的使用样例供参考。该库采用LGPL发行,对商业应用友好。使用OpenCvSharp,可用C#,VB.NET等语言实现...
在本教程中,我们将深入探讨如何使用Python和OpenCV库进行车道线检测,这是一个入门级的项目,适合初学者学习计算机视觉的基本应用。OpenCV(开源计算机视觉库)是一个强大的工具,广泛应用于图像处理和计算机视觉...
61 标准霍夫变换:HoughLines()函数的使用 7.2.4 62 累计概率霍夫变换:HoughLinesP()函数 7.2.5 63 霍夫圆变换:HoughCircles()函数 7.2.8 64 综合示例:霍夫变换 7.2.9 65 实现重映射:remap()函数 7.3.3 66 综合...
OpenCV3还包含了多种图像和视频分析工具,如轮廓检测、霍夫变换等,可帮助开发者实现复杂的应用。 最后,OpenCV3的社区活跃,提供了大量的教程、示例代码和问题解答,这对于学习和解决问题非常有帮助。通过阅读这份...
在描述中提到的"《OpenCV3编程入门》中7.2.4的示例程序",这是一个学习资源,旨在帮助读者理解如何在C#环境下使用EMGU 3.4.1版本实现霍夫变换HoughLines。EMGU库为C#程序员提供了丰富的图像处理函数,包括霍夫变换...
3. 形状检测:OpenCV提供了霍夫变换(HoughLines, HoughCircles)来检测图像中的直线和圆形,这对于交通标志识别或物体定位很有帮助。 4. 特征匹配:SIFT、SURF、ORB等算法用于在不同图像中找到相同的特征点,这...
- **形状匹配**:使用霍夫变换进行直线、圆、椭圆检测。 - **特征检测与描述**:如SIFT、SURF、ORB等,用于图像匹配和识别。 4. **教程内容** "tt_opencv"可能包含以下内容: - **安装OpenCV**:指导如何通过...
- 霍夫变换:是一种在图像中检测几何形状(如直线和圆)的常用技术。 - 像素变换:包括图像金字塔、仿射变换、重映射等,这些都是图像变换和图像缩放中的关键概念。 - 直方图操作:OpenCV提供了一系列处理图像直方...
6. **轮廓检测与形状分析**:通过Canny边缘检测、霍夫变换找到图像中的轮廓,进而进行形状分析和识别。 7. **物体识别与追踪**:利用模板匹配、背景减除、光流法等技术进行物体检测和追踪。 8. **深度学习与OpenCV...
- **霍夫变换**:用于检测图像中的直线和圆等几何形状。 - **重映射**:通过坐标变换实现图像的扭曲和旋转。 - **拉伸、收缩、扭曲和旋转**:更复杂的图像变形操作。 - **CartToPolar与PolarToCart**:坐标系之间的...
- **圆检测**:使用 `HoughCircles()` 函数检测圆形。 - **参数调整**:调整累积器阈值、半径范围等参数。 ##### 3.13 映射变换 - **基本概念**:映射变换的基本思想。 - **应用实例**:使用 `remap()` 函数实现...