




已阅读5页,还剩29页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
本系列文章由 浅墨_ 毛星云 出品,转载请注明出处。 文章链接: /poem_qianmo/article/details/26977557 作者:毛星云(浅墨) 微博:/u/1723155442 知乎:/people/mao-xing-yun 邮箱: 写作当前博文时配套使用的 OpenCV 版本: 2.4.9 本篇文章中,我们一起探讨了 OpenCV 中霍夫变换相关的知识点,以及了解了 OpenCV 中实现霍夫线 变换的 HoughLines、HoughLinesP 函数的使用方法,实现霍夫圆变换的 HoughCircles 函数的使用方 法。此博文一共有四个配套的简短的示例程序,其详细注释过的代码都在文中贴出,且文章最后提供了综 合示例程序的下载。 先尝鲜一下其中一个示例程序的运行截图: 一、引言 在图像处理和计算机视觉领域中,如何从当前的图像中提取所需要的特征信息是图像识别的关键所在。在 许多应用场合中需要快速准确地检测出直线或者圆。其中一种非常有效的解决问题的方法是霍夫 (Hough)变换,其为图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也有很多改进 算法。最基本的霍夫变换是从黑白图像中检测直线(线段)。这篇文章就将介绍 OpenCV 中霍夫变换的使 用方法和相关知识。 二、霍夫变换概述 霍夫变换(Hough Transform)是图像处理中的一种特征提取技术,该过程在一个参数空间中通过计算累计 结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换结果。 霍夫变换于 1962 年由 PaulHough 首次提出,最初的 Hough 变换是设计用来检测直线和曲线,起初的 方法要求知道物体边界线的解析方程,但不需要有关区域位置的先验知识。这种方法的一个突出优点是分 割结果的 Robustness,即对数据的不完全或噪声不是非常敏感。然而,要获得描述边界的解析表达常常是 不可能的。 后于 1972 年由 Richard Duda 11. /-【main( )函数】- - 12. / 描述:控制台应用程序的入口函数,我们的程序从这里开始 13. /- - 14. int main( ) 15. 16. /【1】载入原始图和 Mat 变量定义 17. Mat srcImage = imread(“1.jpg“); /工程目录下应该有一张名为 1.jpg 的素材图 18. Mat midImage,dstImage;/临时变量和目标图的定义 19. 20. /【2】进行边缘检测和转化为灰度图 21. Canny(srcImage, midImage, 50, 200, 3);/进行一此 canny 边缘检测 22. cvtColor(midImage,dstImage, CV_GRAY2BGR);/转化边缘检测后的图为灰度图 23. 24. /【3】进行霍夫线变换 25. vector lines;/定义一个矢量结构 lines 用于存放得到的线段矢量集合 26. HoughLines(midImage, lines, 1, CV_PI/180, 150, 0, 0 ); 27. 28. /【4】依次在图中绘制出每条线段 29. for( size_t i = 0; i 5. #include 6. 7. /-【命名空间声明部分】- - 8. / 描述:包含程序所使用的命名空间 9. /- - 10. using namespace cv; 11. /-【main( )函数】- - 12. / 描述:控制台应用程序的入口函数,我们的程序从这里开始 13. /- - 14. int main( ) 15. 16. /【1】载入原始图和 Mat 变量定义 17. Mat srcImage = imread(“1.jpg“); /工程目录下应该有一张名为 1.jpg 的素材图 18. Mat midImage,dstImage;/临时变量和目标图的定义 19. 20. /【2】进行边缘检测和转化为灰度图 21. Canny(srcImage, midImage, 50, 200, 3);/进行一此 canny 边缘检测 22. cvtColor(midImage,dstImage, CV_GRAY2BGR);/转化边缘检测后的图为灰度图 23. 24. /【3】进行霍夫线变换 25. vector lines;/定义一个矢量结构 lines 用于存放得到的线段矢量集合 26. HoughLinesP(midImage, lines, 1, CV_PI/180, 80, 50, 10 ); 27. 28. /【4】依次在图中绘制出每条线段 29. for( size_t i = 0; i 在霍夫梯度法中,我们使用 Sobel 导数来计算局部梯度,那么随之而来的假设是,其可以视作等同 于一条局部切线,并这个不是一个数值稳定的做法。在大多数情况下,这样做会得到正确的结果,但或许 会在输出中产生一些噪声。 在边缘图像中的整个非 0 像素集被看做每个中心的候选部分。因此,如果把累加器的阈值设置偏低, 算法将要消耗比较长的时间。第三,因为每一个中心只选择一个圆,如果有同心圆,就只能选择其中的一 个。 因为中心是按照其关联的累加器值的升序排列的,并且如果新的中心过于接近之前已经接受的中心的 话,就不会被保留下来。且当有许多同心圆或者是近似的同心圆时,霍夫梯度法的倾向是保留最大的一个 圆。可以说这是一种比较极端的做法,因为在这里默认 Sobel 导数会产生噪声,若是对于无穷分辨率的 平滑图像而言的话,这才是必须的。 4.3 HoughCircles( )函数详解 HoughCircles 函数可以利用霍夫变换算法检测出灰度图中的圆。它和之前的 HoughLines 和 HoughLinesP 比较明显的一个区别是它不需要源图是二值的,而 HoughLines 和 HoughLinesP 都需要 源图为二值图像。 cpp view plaincopyprint? 1. C+: void HoughCircles(InputArray image,OutputArray circles, int method, double dp, double minDist, double param1=100,double param2=100, int minRadius=0, int maxRadius=0 ) 第一个参数,InputArray 类型的 image,输入图像,即源图像,需为 8 位的灰度单通道图像。 第二个参数,InputArray 类型的 circles,经过调用 HoughCircles 函数后此参数存储了检测到 的圆的输出矢量,每个矢量由包含了 3 个元素的浮点矢量(x, y, radius)表示。 第三个参数,int 类型的 method,即使用的检测方法,目前 OpenCV 中就霍夫梯度法一种可以 使用,它的标识符为 CV_HOUGH_GRADIENT,在此参数处填这个标识符即可。 第四个参数,double 类型的 dp,用来检测圆心的累加器图像的分辨率于输入图像之比的倒数, 且此参数允许创建一个比输入图像分辨率低的累加器。上述文字不好理解的话,来看例子吧。例 如,如果 dp= 1 时,累加器和输入图像具有相同的分辨率。如果 dp=2,累加器便有输入图像 一半那么大的宽度和高度。 第五个参数,double 类型的 minDist,为霍夫变换检测到的圆的圆心之间的最小距离,即让我 们的算法能明显区分的两个不同圆之间的最小距离。这个参数如果太小的话,多个相邻的圆可能 被错误地检测成了一个重合的圆。反之,这个参数设置太大的话,某些圆就不能被检测出来了。 第六个参数,double 类型的 param1,有默认值 100。它是第三个参数 method 设置的检测方 法的对应的参数。对当前唯一的方法霍夫梯度法 CV_HOUGH_GRADIENT,它表示传递给 canny 边缘检测算子的高阈值,而低阈值为高阈值的一半。 第七个参数,double 类型的 param2,也有默认值 100。它是第三个参数 method 设置的检测 方法的对应的参数。对当前唯一的方法霍夫梯度法 CV_HOUGH_GRADIENT,它表示在检测阶 段圆心的累加器阈值。它越小的话,就可以检测到更多根本不存在的圆,而它越大的话,能通过 检测的圆就更加接近完美的圆形了。 第八个参数,int 类型的 minRadius,有默认值 0,表示圆半径的最小值。 第九个参数,int 类型的 maxRadius,也有默认值 0,表示圆半径的最大值。 需要注意的是,使用此函数可以很容易地检测出圆的圆心,但是它可能找不到合适的圆半径。我们可以通 过第八个参数 minRadius 和第九个参数 maxRadius 指定最小和最大的圆半径,来辅助圆检测的效果。 或者,我们可以直接忽略返回半径,因为它们都有着默认值 0,单单用 HoughCircles 函数检测出来的圆 心,然后用额外的一些步骤来进一步确定半径。 依然是为大家准备了基于此函数的示例程序: cpp view plaincopyprint? 1. /-【头文件包含部分】- - 2. / 描述:包含程序所依赖的头文件 3. /- 4. #include 5. #include 6. 7. /-【命名空间声明部分】- - 8. / 描述:包含程序所使用的命名空间 9. /- - 10. using namespace cv; 11. /-【main( )函数】- - 12. / 描述:控制台应用程序的入口函数,我们的程序从这里开始 13. /- - 14. int main( ) 15. 16. /【1】载入原始图和 Mat 变量定义 17. Mat srcImage = imread(“1.jpg“); /工程目录下应该有一张名为 1.jpg 的素材图 18. Mat midImage,dstImage;/临时变量和目标图的定义 19. 20. /【2】显示原始图 21. imshow(“【原始图】“, srcImage); 22. 23. /【3】转为灰度图,进行图像平滑 24. cvtColor(srcImage,midImage, CV_BGR2GRAY);/转化边缘检测后的图为灰度图 25. GaussianBlur( midImage, midImage, Size(9, 9), 2, 2 ); 26. 27. /【4】进行霍夫圆变换 28. vector circles; 29. HoughCircles( midImage, circles, CV_HOUGH_GRADIENT,1.5, 10, 200, 100, 0, 0 ); 30. 31. /【5】依次在图中绘制出圆 32. for( size_t i = 0; i storage = cvCreateMemStorage(STORAGE_SIZE); 6. Mat image = _image.getMat(); 7. CvMat c_image = image; 8. CvSeq* seq = cvHoughLines2( 11. seqToMat(seq, _lines); 12. 可以发现其内部实现是基于 OpenCV 1.X 旧版的 cvHoughLines2 函数,我们再来看看其旧版 cvHoughLines2 的函数源码。 5.1.1 OpenCV2.X 中 cvHoughLines2()函数源码 cpp view plaincopyprint? 1. CV_IMPL CvSeq* 2. cvHoughLines2( CvArr* src_image, void*lineStorage, int method, 3. double rho, double theta, intthreshold, 4. double param1, double param2 ) 5. 6. CvSeq* result = 0; 7. 8. CvMat stub, *img = (CvMat*)src_image; 9. CvMat* mat = 0; 10. CvSeq* lines = 0; 11. CvSeq lines_header; 12. CvSeqBlock lines_block; 13. int lineType, elemSize; 14. int linesMax = INT_MAX; 15. int iparam1, iparam2; 16. 17. img = cvGetMat( img, 18. 19. if( !CV_IS_MASK_ARR(img) 20. CV_Error( CV_StsBadArg, “The source image must be 8-bit,single-channel“ ); 21. 22. if( !lineStorage ) 23. CV_Error( CV_StsNullPtr, “NULL destination“ ); 24. 25. if( rho type ) | (mat-rows != 1 50. 51. if( CV_MAT_TYPE( mat-type ) != lineType ) 52. CV_Error( CV_StsBadArg, 53. “The destination matrix data type is inappropriate, see themanual“ ); 54. 55. lines = cvMakeSeqHeaderForArray( lineType, sizeof(CvSeq), elemSize,mat- data.ptr, 56. mat-rows + mat-cols - 1, 57. linesMax = lines-total; 58. cvClearSeq( lines ); 59. 60. else 61. CV_Error( CV_StsBadArg, “Destination is not CvMemStorage* norCvMat*“ ); 62. 63. iparam1 = cvRound(param1); 64. iparam2 = cvRound(param2); 65. 66. switch( method ) 67. 68. case CV_HOUGH_STANDARD: 69. icvHoughLinesStandard( img, (float)rho, 70. (float)theta, threshold,lines, linesMax ); 71. break; 72. case CV_HOUGH_MULTI_SCALE: 73. icvHoughLinesSDiv( img, (float)rho, (float)theta, 74. threshold, iparam1, iparam2,lines, linesMax ); 75. break; 76. case CV_HOUGH_PROBABILISTIC: 77. icvHoughLinesProbabilistic( img, (float)rho, (float)theta, 78. threshold, iparam1, iparam2,lines, linesMax ); 79. break; 80. default: 81. CV_Error( CV_StsBadArg, “Unrecognized method id“ ); 82. 83. 84. if( mat ) 85. 86. if( mat-cols mat-rows ) 87. mat-cols = lines-total; 88. else 89. mat-rows = lines-total; 90. 91. else 92. result = lines; 93. 94. return result; 95. 5.2 OpenCV2.X 中 HoughLinesP()函数源码 cpp view plaincopyprint? 1. void cv:HoughLinesP( InputArray _image,OutputArray _lines, 2. double rho, double theta,int threshold, 3. double minLineLength,double maxGap ) 4. 5. Ptr storage = cvCreateMemStorage(STORAGE_SIZE); 6. Mat image = _image.getMat(); 7. CvMat c_image = image; 8. CvSeq*seq = cvHoughLines2( 10. seqToMat(seq, _lines); 11. 可以发现其内部内部实现依然是基于旧版 OpenCV 1.X 的 cvHoughLines2 函数的,上面我们已经将 cvHoughLines2()贴出来了,这里就不再次贴出了。 5.3 OpenCV2.X 中 HoughCircles()函数源码 cpp view plaincopyprint? 1. void cv:HoughCircles( InputArray _image,OutputArray _circles, 2. int method, double dp,double min_dist, 3. double param1, doubleparam2, 4. int minRadius, int maxRadius ) 5. 6. Ptr storage = cvCreateMemStorage(STORAGE_SIZE); 7. Mat image = _image.getMat(); 8. CvMat c_image = image; 9. CvSeq* seq = cvHoughCircles( 11. seqToMat(seq, _circles); 12. 可以发现其内部内部实现是基于旧版 OpenCV 1.X 的 cvHoughCircles,我们再来看看其旧版 cvHoughCircles( )的函数源码。 5.3.1 OpenCV2.X 中 cvHoughCircles()函数源码 cpp view plaincopyprint? 1. CV_IMPL CvSeq* 2. cvHoughCircles( CvArr* src_image, void*circle_storage, 3. int method, double dp, doublemin_dist, 4. double param1, double param2, 5. int min_radius, int max_radius) 6. 7. CvSeq* result = 0; 8. 9. CvMat stub, *img = (CvMat*)src_image; 10. CvMat* mat = 0; 11. CvSeq* circles = 0; 12. CvSeq circles_header; 13. CvSeqBlock circles_block; 14. int circles_max = INT_MAX; 15. int canny_threshold = cvRound(param1); 16. int acc_threshold = cvRound(param2); 17. 18. img = cvGetMat( img, 19. 20. if( !CV_IS_MASK_ARR(img) 21. CV_Error( CV_StsBadArg, “The source image must be 8-bit,single-channel“ ); 22. 23. if( !circle_storage ) 24. CV_Error( CV_StsNullPtr, “NULL destination“ ); 25. 26. if( dp rows, img-cols ); 32. else if( max_radius type ) | (mat-rows != 1 48. 49. circles = cvMakeSeqHeaderForArray( CV_32FC3, sizeof(CvSeq),sizeof(float)*3, 50. mat-data.ptr, mat-rows +mat-cols - 1, 51. circles_max = circles-total; 52. cvClearSeq( circles ); 53. 54. else 55. CV_Error( CV_StsBadArg, “Destination is not CvMemStorage* norCvMat*“ ); 56. 57. switch( method ) 58. 59. case CV_HOUGH_GRADIENT: 60. icvHoughCirclesGradient( img, (float)dp, (float)min_dist, 61. min_radius,max_radius, canny_threshold, 62. acc_threshold,circles, circles_max ); 63. break; 64. default: 65. CV_Error( CV_StsBadArg, “Unrecognized method id“ ); 66. 67. 68. if( mat ) 69. 70. if( mat-cols mat-rows ) 71. mat-cols = circles-total; 72. else 73. mat-rows = circles-total; 74. 75. else 76. result = circles; 77. 78. return result; 79. 五、综合示例部分 这次的综合示例,浅墨在 HoughLinesP 函数的基础上,为其添加了用于控制其第五个参数阈值 threshold 的滚动条。于是便能通过调节滚动条,改变阈值,动态地控制霍夫线变换检测的线条多少。 废话不多说,直接上详细注释的代码: cpp view plaincopyprint? 1. /-【程序说明】- - 2. / 程序名称::【OpenCV 入门教程之十四】OpenCV 霍夫变换:霍夫线变换,霍夫圆变 换合辑 博文配套源码 3. / 开发所用 IDE 版本:Visual Studio 2010 4. / 开发所用 OpenCV 版本: 2.4.9 5. / 2014 年 5 月 26 日 Created by 浅墨 6. /- 7. 8. /-【头文件包含部分】- - 9. / 描述:包含程序所依赖的头文件 10. /- 11. #include 12. #include 13. #include 14. 15. /-【命名空间声明部分】- - 16. / 描述:包含程序所使用的命名空间 17. /- - 18. using namespace std; 19. using namespace cv; 20. 21. 22. /-【全局变量声明部分】- - 23. / 描述:全局变量声明 24. /- - 25. Mat g_srcImage, g_dstImage,g_midImage;/原始图、中间图和效果图 26. vector g_lines;/定义一个矢量结构 g_lines 用于存放得到的线段矢量集合 27. /变量接收的 TrackBar 位置参数 28. int g_nthreshold=100; 29. 30. /-【全局函数声明部分】- - 31. / 描述:全局函数声明 32. /- - 33. 34. static void on_HoughLines(int, void*);/回调函数 35. static void ShowHelpText(); 36. 37. 38. /-【main( )函数】- - 39. / 描述:控制台应用程序的入口函数,我们的程序从这里开始 40. /- - 41. int main( ) 42. 43. /改变 console 字体颜色 44. system(“color 3F“); 45. 46. ShowHelpText(); 47. 48. /载入原始图和 Mat 变量定义 49. Mat g_srcImage = imread(“1.jpg“); /工程目录下应该有一张名为 1.jpg 的素材图 50. 51. /显示原始图 52. imshow(“【原始图】“, g_srcImage); 53. 54. /创建滚动条 55. namedWindow(“【效果图】“,1); 56. createTrackbar(“值“, “【效果图】“, 57. 58. /进行边缘检测和转化为灰度图 59. Canny(g_srcImage, g_midImage, 50, 200, 3);/进行一
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030中国金丝桃素行业市场发展趋势与前景展望战略研究报告
- 2025-2030中国重型机械行业市场深度调研及发展前景与投资研究报告
- 2025-2030中国酒吧POS软件行业市场发展趋势与前景展望战略研究报告
- 2025-2030中国道路清扫车行业发展分析及发展前景与投资研究报告
- 2025-2030中国通信电缆行业市场发展趋势与前景展望战略研究报告
- 2025-2030中国运算跨导放大器(OTA)行业市场发展趋势与前景展望战略研究报告
- 2025-2030中国运动器材及配件行业市场发展趋势与前景展望战略研究报告
- 2025-2030中国输液塑料包装袋行业市场深度调研及价值评估与投资前景研究报告
- 2025-2030中国车身钢板行业发展分析及投资前景预测研究报告
- 2025-2030中国跨境电商系统行业市场发展前瞻及投资战略研究报告
- 2025年度智能硬件产品全国区域独家代理合同3篇
- 办公室安全知识培训课件
- 2025年四川省成都市青白江区招聘50人历年高频重点提升(共500题)附带答案详解
- 2025年浙江嘉兴市众业供电服务限公司招聘38人高频重点提升(共500题)附带答案详解
- 【课件】第12课+理想与典范-古希腊与古罗马美术+课件高中美术人教版(2019)美术鉴赏
- 建筑行业安全隐患举报奖励机制
- 公司事故隐患内部报告奖励机制
- Unit10 How to stay safe 教学设计-2023-2024学年教科版(广州)英语五年下册
- 小学生诗词大赛练习资料
- 铝板幕墙监理细则
- 全过程工程咨询管理服务方案投标方案(技术方案)
评论
0/150
提交评论