开发环境为:win10+QT5.8+opencv3.2

Hough变换是图像处理中从图像中识别几何形状的基本方法之一,应用很广泛。最基本的Hough变换是从黑白图像中检测直线,还可以经过改进检测圆、椭圆、正方形等。本文主要实现Hough直线检测、Hough圆检测、Hough椭圆检测。

一、读取图像

读取图像见QT+opencv学习笔记(1)——图像点运算,这里不再赘述。

读取结果如下图:

二、Hough直线检测

使用Hough变换进行直线检测, 首先要从原始图像中提取出边缘信息, 将原图转换成一个二值化的边缘轮廓图, 然后将这个二值边缘图中的采样点映射到Hough参数空间中的直线b=-xa+y, 在参数空间中绘制出直线后,在每一个点上进行统计,点的数值代表参数空间中穿过该点直线的数目。如图1-1所示, 由于图像空间中的点对应于参数空间中的直线, 而图像空间中的直线相应地对应于参数空间中的点, 因此在二维累加器中统计各点数值后所找到超过一定阈值的峰值点就是图像空间中的直线。

图1-1直线Hough变换的对应关系

在具体操作中,通常使用直线的法线式。因为当直线平行于纵轴时,直线方程 y=ax+b中参数a趋于无穷大,无法在参数空间中进行统计,而使用直线的法线式可以检测出这类直线。图像空间x-y中的直线法线式如下:

其中,ρ为直线L到原点的距离;θ为直线 L与x轴正方向的夹角,根据上式,直线L 上不同的点在参数平面ρ-θ中被变换为一簇相交于t点的正弦曲线。显然,若能确定参数平面中的t点,就实现了直线检测。在实际计算中,根据图像空间中的数据点计算Hough 参数空间中的正弦曲线轨迹,在参数平面上进行二维统计,选取峰值。该峰值就是图像空间中一条直线的参数,从而实现了图像空间中的直线检测。

在opencv中分别有HoughLines()函数和HoughLinesP()函数可以实现Hough直线检测。

HoughLines()函数实现方式为标准霍夫变换。标准霍夫变换本质上是把图像映射到它的参数空间上,它需要计算所有的M个边缘点,这样它的运算量和所需内存空间都会很大。 HoughLines()函数定义如下:

void HoughLines(InputArray image,    //8位单通道二值图像,函数可能会修改输入图像,所以不要使用原图OutputArray lines,   //输出直线向量,两个元素的向量(ρ,θ)代表一条直线,ρ是从原点(图像的左上角)的距离//θ是直线的角度(单位是弧度),0表示垂直线,π/2表示水平线 double rho,          //距离分辨率 double theta,        //角度分辨率int threshold,       //阈值,只有大于该值的点在霍夫空间变换中才有可能被当作极大值 double srn=0,        //用于多尺度霍夫变换double stn=0 )       //用于多尺度霍夫变换

主要代码如下:

Canny( srcImg, lineImg, 50, 200, 3 );cvtColor( lineImg, color_lineImg, CV_GRAY2BGR );vector<Vec2f> lines;HoughLines( lineImg, lines, 1, CV_PI/180, 100 );for( size_t i = 0; i < lines.size(); i++ ){float rho = lines[i][0];float theta = lines[i][1];double a = cos(theta), b = sin(theta);double x0 = a*rho, y0 = b*rho;Point pt1(cvRound(x0 + 1000*(-b)),cvRound(y0 + 1000*(a)));Point pt2(cvRound(x0 - 1000*(-b)),cvRound(y0 - 1000*(a)));line( color_lineImg, pt1, pt2, Scalar(0,0,255), 3, 8 );}

霍夫变换直线检测结果如下:

如果在输入图像中只是处理m(m<M)个边缘点,则这m个边缘点的选取是具有一定概率性的,因此该方法被称为概率霍夫变换(Probabilistic Hough Transform)。该方法还有一个重要的特点就是能够检测出线端,即能够检测出图像中直线的两个端点,确切地定位图像中的直线。

HoughLinesP函数就是利用概率霍夫变换来检测直线的。它的一般步骤为:
        1、随机抽取图像中的一个特征点,即边缘点,如果该点已经被标定为是某一条直线上的点,则继续在剩下的边缘点中随机抽取一个边缘点,直到所有边缘点都抽取完了为止;
        2、对该点进行霍夫变换,并进行累加和计算;
        3、选取在霍夫空间内值最大的点,如果该点大于阈值的,则进行步骤4,否则回到步骤1;
        4、根据霍夫变换得到的最大值,从该点出发,沿着直线的方向位移,从而找到直线的两个端点;

5、计算直线的长度,如果大于某个阈值,则被认为是好的直线输出,回到步骤1。

HoughLinesP()函数定义如下:

void HoughLinesP(InputArray image,       //8位单通道二值图像,函数可能会修改输入图像,所以不要使用原图OutputArray lines,      //输出的直线向量,每条线用4个元素表示,即直线的两个端点的4个坐标值double rho,             //距离分辨率double theta,           //角度分辨率int threshold,          //阈值,它表示要判断为一条直线所需的最少度量,显然这个值越大,//所判断出的直线越少;这个值越小,所判断出的直线越多。double minLineLength=0, //根据threshold提取出的直线长短不一,这个参数以长度对这些直线作一次筛选,//小于这个参数值的就被抛弃。显然这个值越大,所判断出的直线越少;这个值越小,所判断出的直线越多。double maxLineGap=0     //最大直线间隙,即如果有两条线段在一条直线上,但它们之间因为有间隙,所以被认为是两个线段,//如果这个间隙大于该值,则被认为是两条线段,否则是一条。显然这个值越大,所判断出的直线越少;//这个值越小,所判断出的直线越多(值越小,那么间隙值就越容易大于这个值)。)

主要代码如下:

Canny( srcImg, lineImg, 50, 200, 3 );cvtColor( lineImg, color_lineImg, CV_GRAY2BGR );vector<Vec4i> lines;HoughLinesP( lineImg, lines, 1, CV_PI/180, 80, 30, 10 );for( size_t i = 0; i < lines.size(); i++ ){line( color_lineImg, Point(lines[i][0], lines[i][1]),Point(lines[i][2], lines[i][3]), Scalar(0,0,255), 3, 8 );}//imshow( "Detected Lines", color_lineImg );

概率霍夫变换直线检测结果如下:

三、Hough圆检测

霍夫圆检测的基本原理霍夫直线检测类似, 只是点对应的二维极径极角空间被三维的圆心点x, y还有半径r空间取代。

对直线来说, 一条直线能由参数极径极角 (r, θ) 表示。而对圆来说, 我们需要三个参数来表示一个圆, 现在原图像的边缘图像的任意点对应的经过这个点的所有可能圆是在三维空间有下面这三个参数来表示了,其对应一条三维空间的曲线。那么与二维的霍夫线变换同样的道理, 对于多个边缘点越多这些点对应的三维空间曲线交于一点那么他们经过的共同圆上的点就越多,类似的我们也就可以用同样的阈值的方法来判断一个圆是否被检测到, 这就是标准霍夫圆变换的原理, 但也正是在三维空间的计算量大大增加的原因, 标准霍夫圆变化很难被应用到实际中。

出于上面提到的对运算效率的考虑, OpenCV实现的是一个比标准霍夫圆变换更为灵活的检测方法: 霍夫梯度法, 也叫2-1霍夫变换(21HT), 它的原理依据是圆心一定是在圆上的每个点的模向量上, 这些圆上点模向量的交点就是圆心, 霍夫梯度法的第一步就是找到这些圆心, 这样三维的累加平面就又转化为二维累加平面. 第二步根据所有候选中心的边缘非0像素对其的支持程度来确定半径。霍夫圆检测可以通过HoughCircles()函数来实现。

HoughCircles()函数定义如下:

void HoughCircles(InputArray image,     //8位单通道灰度图OutputArray circles,  //找到的圆的输出向量,每个向量用(x, y, radius)来表示int method,           //检测方法CV_HOUGH_GRADIENT,现在OpenCV中只有霍夫梯度法 double dp,            //累加器分辨率相对于图像分辨率的比率double minDist,       //检测出的圆心之间的最小距离double param1=100,    //Canny边缘函数的高阈值 double param2=100,    //检测圆心的累加器的阈值int minRadius=0,      //最小圆半径int maxRadius=0       //最大圆半径)

主要代码如下:

Mat grayImg = srcImg.clone();Mat colorImg;cvtColor(grayImg, colorImg, CV_GRAY2BGR);//平滑图像GaussianBlur( grayImg, grayImg, Size(9, 9), 2, 2 );vector<Vec3f> circles;HoughCircles(grayImg, circles, CV_HOUGH_GRADIENT,2, grayImg.rows/4, 200, 150 );for( size_t i = 0; i < circles.size(); i++ ){Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));int radius = cvRound(circles[i][2]);//绘制圆心circle( colorImg, center, 3, Scalar(0,255,0), -1, 8, 0 );//绘制圆的边circle( colorImg, center, radius, Scalar(0,0,255), 3, 8, 0 );}

Hough圆检测处理结果如下:

四、Hough椭圆检测

椭圆几何定理:设平面上有一个椭圆,点c为椭圆圆心,任取平面上一点p(不同于点c),点p距椭圆上点的最大距离一定大于点 c距椭圆上点的最大距离。
        下面介绍所采用的椭圆检测方法。其指导思想是利用上面的椭圆几何定理,通过查找距离椭圆上点最大距离最小的点来找到圆心,同时这个最小的最大距离就是椭圆的长轴长度。通过这种方法,椭圆的5个参数(椭圆圆心点横、纵坐标,长、短轴长,旋转角度)得到了3个,剩下的2个参数就可以在二维参数空间上统计了,即可以采用Hough变换检测直线的相同方法来检测椭圆了。
        算法的具体操作步骤如下:
        (1)对要处理的图像进行边缘检测,得到二值化的边缘轮廓图,将边缘图上的点存入数组A。
        (2)对二维平面上的每一点,计算与上一步所得数组A中点的距离,得到每一点距数组A 中点的最大距离,所有点中最大距离最小的点即是椭圆圆心(p,q),该最大距离即是椭圆长轴长度 a。
        (3)将数组A中每一点的数值和刚才得到的3个椭圆参数p、q、a代入椭圆方程E:

在二维参数空间上对参数b、θ进行统计,得到峰值超过一定阈值的一组参数即为椭圆。

主要代码如下:

Mat grayImg = srcImg.clone();Mat colorImg;cvtColor(grayImg, colorImg, CV_GRAY2BGR);GaussianBlur(grayImg, grayImg, Size(3,3), 0, 0); //高斯平滑Canny(grayImg, grayImg, 100, 200, 3);            //Canny边缘检测namedWindow("Canny", CV_WINDOW_AUTOSIZE);imshow("Canny", grayImg);//提取轮廓vector<vector<Point>>  contours;vector<Vec4i> hierarchy;findContours(grayImg,contours,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);//绘制查找到的轮廓//drawContours(colorImg, contours, -1, Scalar(0,255,0));//imshow("cour.bmp",colorImg);//Hough变换int accumulate;   // Hough空间最大累积量Ellipse myellipse;Mat elliImg(grayImg.size(),CV_8UC3,Scalar(0));for(int i=0;i< contours.size();i++){myellipse.Computer_axy(contours[i],grayImg.size());accumulate=myellipse.hough_ellipse(contours[i]);//cout<<"accumulate:"<<accumulate<<endl;//cout<<"contours[i].size():"<<contours[i].size()<<endl;// 判断是否超过给定阈值,判断是否为椭圆,并通过长轴与短轴的轴长差去除干扰if(accumulate>=contours[i].size()*0.25 && abs(myellipse.getLongAxis()-myellipse.getShortAxis())>2.0&& abs(myellipse.getLongAxis()-myellipse.getShortAxis())<50.0)elliImg=myellipse.draw_Eliipse(colorImg);}
通过轮廓提取得到边界轮廓点,并存入容器。轮廓提取可参见QT+opencv学习笔记(4)——边缘检测、轮廓提取及轮廓跟踪
        Hough椭圆检测处理结果如下:

整体工程代码见QT+opencv霍夫直线检测,圆检测及椭圆检测

参考:

(1)OpenCV霍夫系列(后篇)-统计概率霍夫变换(HoughLinesP)

(2)opencv 霍夫圆检测

(3)Hough变换检测椭圆 附带matlab与opencv代码

QT+opencv学习笔记(5)——霍夫直线检测、圆检测及椭圆检测相关推荐

  1. OpenCV学习笔记(二十六)——小试SVM算法ml OpenCV学习笔记(二十七)——基于级联分类器的目标检测objdect OpenCV学习笔记(二十八)——光流法对运动目标跟踪Video Ope

    OpenCV学习笔记(二十六)--小试SVM算法ml 总感觉自己停留在码农的初级阶段,要想更上一层,就得静下心来,好好研究一下算法的东西.OpenCV作为一个计算机视觉的开源库,肯定不会只停留在数字图 ...

  2. OpenCV学习笔记(二十一)——绘图函数core OpenCV学习笔记(二十二)——粒子滤波跟踪方法 OpenCV学习笔记(二十三)——OpenCV的GUI之凤凰涅槃Qt OpenCV学习笔记(二十

    OpenCV学习笔记(二十一)--绘图函数core 在图像中,我们经常想要在图像中做一些标识记号,这就需要绘图函数.OpenCV虽然没有太优秀的GUI,但在绘图方面还是做得很完整的.这里就介绍一下相关 ...

  3. Qt+openCV学习笔记(五)Qt5.15.2+openCV4.5.4+VS2019_64编译动态库

    前言 opencv官方只提供基本的库,若是用到其他库,需要自己编译.通常只要编译自己需要的模块就可以了,本次编译过程可供大家参考 本次编译的,是未带CUDA加速的版本 假设Qt.VS2019已正常安装 ...

  4. OpenCV标准霍夫直线检测详解

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转载自:OpenCV学堂 霍夫直线检测 对于图像来说可以从笛卡 ...

  5. OpenCV霍夫直线houghlines点集的实例(附完整代码)

    OpenCV霍夫直线houghlines点集的实例 OpenCV霍夫直线houghlines点集的实例 OpenCV霍夫直线houghlines点集的实例 #include <opencv2/c ...

  6. OpenCV霍夫直线检测的实例(附完整代码)

    OpenCV霍夫直线检测的实例 OpenCV霍夫直线检测的实例 OpenCV霍夫直线检测的实例 #include <opencv2/imgproc.hpp> #include <op ...

  7. OpenCV中霍夫直线变换

    OpenCV中霍夫直线变换 首先要知道,一条直线的通用表达式为y=ax+b\color{#F00}y=ax+by=ax+b,a为直线的斜率,b为直线的截距,知道这两个参数可以唯一确定一条直线.通常我们 ...

  8. android openCV检测图像的基本特征,包括Canny边缘检测、Harris角点检测、霍夫直线检测-基于Android studio

    实现平台:windows下的Android studio1.4 依赖库:openCV3.1.0 程序安装平台:Android6.0 实现的功能:从手机中选择一张图片,检测图片的基本特征,通过menu菜 ...

  9. c++版本opencv(36.霍夫直线检测37.直线类型与线段-)

    c++版本opencv(36.霍夫直线检测37.直线类型与线段-) 一.36.霍夫直线检测- 二,37.直线类型与线段- 来自网易云课堂贾志刚老师 一.36.霍夫直线检测- 同一条直线上的点,r和c塔 ...

最新文章

  1. python keyboard模块_python3 安装 pykeyboard 模拟浏览器
  2. elasticsearch按照配置时遇到的一些坑 [Failed to load settings from [elasticsearch.yml]]
  3. 技术干货| 阿里云基于Hudi构建Lakehouse实践探索「内附干货PPT下载渠道」
  4. 分布式事务框架-TX-LCN
  5. python添加包路径_python包/模块路径
  6. 在IntelliJ IDEA中clone项目代码
  7. 电脑更新系统时间显示rpc服务器不可用,win7系统时间同步出错RPC服务器不可用的解决方法...
  8. udhcpc 的使用
  9. 从0到100:基于微信小程序的羽毛球馆预约系统的开发笔记
  10. 【计算机网络学习笔记02】计算机网络概述(中)
  11. 商用密码产品认证-智能IC卡
  12. BERT知识蒸馏TinyBERT
  13. 早秋山居 --温庭筠[唐.五言律诗]
  14. Linux下打开word等office文件(openoffice安装)
  15. python:实现由伪栈表示的队列算法(附完整源码)
  16. 如何取消Office 正版增值验证
  17. zemax 学习笔记
  18. java 七巧板油漆问题_七巧板的问题
  19. 原生JS无缝轮播图(左右切换、导航跟随)
  20. SitePoint播客#100直播!

热门文章

  1. “撒旦”勒索病毒再曝4.2变种 腾讯电脑管家文档守护者可一招解密
  2. Python super(钻石继承)
  3. 苹果手机iCloud备忘录删除怎么恢复
  4. R语言使用epiDisplay包的summ函数计算向量数据在不同分组下的描述性统计汇总信息并可视化有序点图(名称、有效值个数、均值、中位数、标准差、最大值、最小值)
  5. 常用快捷键大全Win7快捷键
  6. 关于VMware虚拟机中调节图标字体大小
  7. java链接易联云打印机
  8. 关于SD卡原理图和实际封装区别的探索
  9. 京东评论情感分类器(基于bag-of-words模型)
  10. java计算机毕业设计校园订餐系统源代码+数据库+系统+lw文档