1.霍夫变换综述

霍夫变换是图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也有很多改进算法。主要用来从图像中分离出具有某种相同特征的几何形状。最基本的霍夫变换是从黑白图像中检测直线。在图像处理中可以通过霍夫变换可以快速的检测出直线或圆。

2.霍夫线变换

opencv提供三种不同的霍夫线变换分别是:标准霍夫变换(Standard Hough Transform, SHT)、多尺度霍夫 变换(Multi-Scale Hough Transform, MSHT)和累计概率霍夫变换(Progressive Probabilistic Hough Transform, PPHT).其中多尺度霍夫变换(MSHT)为经典霍夫变换(SHT)在多尺度下的一个变种。而累计概率霍夫变换(PPHT)算法是标准霍夫变换(SHT)算法的一个改进,它在一定的范围内进行霍夫变换,计算单独线段的方向以及范围,从而减少计算量,缩短计算时间。之所以称PPHT为概率的事因为并不将累加器平面内的所有可能的点累加,而只是累加其中的一部分,想法是如果峰值足够高,只用一小部分时间去寻找它就够了。(本段参考博文地址:http://blog.csdn.net/poem_qianmo/article/details/26977557)
在opencv中可以用HoughLines函数来调用标准霍夫变换(SHT)和多尺度霍夫变换(MSHT).而HoughLinesP函数用于调用累计概率霍夫变换PPHT。累计概率霍夫变换执行效率很高。
霍夫线变换是用来寻找直线的方法,在使用霍夫线变换之前首先要对图像进行边缘检测的处理,也即霍夫线变换的直接输入只能是边缘二值图像。
霍夫线变换实现原理如下:
(1). 众所周知,一条直线在图像二维空间可由两个变量表示。如:

  • a.在笛卡尔坐标系:可由参数(m, b)斜率和截距表示。
  • b.在极坐标系:可由参数(r, θ)极径和极角表示

    对于霍夫变换,我们将用极坐标系来表示直线。因此直线的表达式可为:

    化简的:r=xcosθ+ysinθ
    (2). 一般来说对于点,我们可以将通过这个点的一簇直线同一定义为:


这就意味着对于每一对代表一条通过点的直线。
(3). 如果对于一个给定点,我们在极坐标对极径极角平面绘出所有通过它的直线,将得到一条正弦曲线。例如对于给定点我们可以绘出下图:

只绘出满足条件r>0和0<θ<2π。

(4). 我们可以对图像中所有点进行上述操作,如果两个不同点经过上述操作后得到的曲线在平面θ-r相交就意味着它们通过同一条直线。例如接上面的例子,我们继续对点x1=9,y1=4和点x2=12, y2=3绘图得到下图:

这三条曲线在θ-r平面相交于点(0.925, 9.6), 坐标表示的是参数对(θ, r)或者是说点(x0, y0),点(x1, y1)和点(x2, y2)组成的平面内的直线。
(5).上述说明一般来讲,一条能够通过在平面θ-r寻找交于一点的曲线数量检测。越多曲线交于一点也就意味着这个交点表示的直线由更多的点组成。一般来说我们可以通过设置直线上点的阈值来定义多少条曲线交于一点认为检测到了一条直线
(6). 这就是霍夫变换要做的工作,它追中图像中的每个点对应曲线间的交点,如果交于一点的曲线数量超过了阈值,那么可以认为这个交点所代表的参数对(θ, rθ)在原图像中为一条直线

2.1 HoughLines()函数

在opencv中标准霍夫变换(SHT)和多尺度霍夫变换(MSHT)是由HoughLines函数调用的。其定义如下:

void cv::HoughLines  ( InputArray  image,  OutputArray  lines,  double  rho,  double  theta,  int  threshold,  double  srn = 0,  double  stn = 0,  double  min_theta = 0,  double  max_theta = CV_PI  )

参数解释

  • .image: 8位单通道二进制图像,可以载入任意图像由函数修改成此格式
  • .lines: 输出直线矢量,每一条线有两个元素的矢量(ρ
    , θ)表示,ρ是离坐标原点(0, 0)也就是图像左上角的距离,θ是弧度线条旋转角度(0度表示垂直线,π/2度表示水平线)。
  • .rho: 以像素为单位的距离精度,其它表述还有是直线搜索时的进步尺寸的单位半径
  • .theta: 以弧度为单位的角度精度。其它表述还有是直线搜索时的进步尺寸的单位角度。
  • .threshold: 累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值。大于阈值threshold的直线才可以被检测通过并返回到结果中。
  • . srn: 对于多尺度的霍夫变换,这是第三个参数进步尺寸rho的除数距离。粗略的累加器进步尺寸直接是第三个参数rho, 而精确的累加器进步尺寸为rho/srn。有默认值0
  • .stn对于多尺度霍夫变换,stn表示第四个参数进步尺寸的单位角度theta的除数距离。且如果srn和stn同时为0, 就表示使用经典的霍夫变换,扶着这两个参数都应该为正数。经典霍夫变换和多尺度霍夫变换就是在这进行区分的。有默认值0

示例代码

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>using namespace std;
using namespace cv;int main()
{Mat srcImage;srcImage = imread("building.jpg");        //加载图像文件//判断图像是否加载成功if(srcImage.empty()){cout << "图像加载失败!" << endl;return -1;}elsecout << "图像加载成功!" << endl << endl;namedWindow("原图像", WINDOW_AUTOSIZE);imshow("原图像", srcImage);Mat midImage, dstImage;Canny(srcImage, midImage, 50, 200, 3);        //首先对图像进行边缘检测cvtColor(midImage, dstImage, COLOR_GRAY2BGR);//进行霍夫变换vector<Vec2f> lines;            //定义一个矢量结构用于存放得到的线段矢量集合HoughLines(midImage, lines, 1, CV_PI/180,230, 0, 0);//在图中绘出线段for(size_t i = 0; i < lines.size(); i++){float rho = lines[i][0];float theta = lines[i][1];Point pt1, pt2;double a = cos(theta), b = sin(theta);double x0 = a * rho, y0 = b * rho;pt1.x = cvRound(x0 + 1000*(-b));pt1.y = cvRound(y0 + 1000*(a));pt2.x = cvRound(x0 - 1000*(-b));pt2.y = cvRound(y0 - 1000*(a));line(dstImage, pt1, pt2, Scalar(0, 0, 255), 1, LINE_AA);}namedWindow("霍夫线变换", WINDOW_AUTOSIZE);imshow("霍夫线变换", dstImage);waitKey(0);return 0;
}

运行结果

2.2HoughLinesP()函数

其函数定义如下:

void cv::HoughLinesP    (   InputArray      image,OutputArray     lines,double      rho,double      theta,int     threshold,double      minLineLength = 0,double      maxLineGap = 0 )   

参数解释

  • .image: 8位单通道二进制图像,可以载入任意图像由函数修改成此格式
  • .lines: 线段输出矢量,每一条之先都由四个矢量元素(x1, y1, x2, y2)表示,其中(x1, y1)和(x2, y2)分别是检测到直线线段的两个端点。
  • .rho: 以像素为单位的直线搜寻步长
  • .theta: 以弧度为单位的直线搜寻步长
  • .threshold: 累加器阈值参数,只有大于threshold的直线结果才能被检测通过并返回到结果中
  • .minLineLength: 线段长度最小值,如果线段长度小于这个值则线段结果不显示,有默认值0
  • .maxLineGap: 允许点连接到相同直线的中间距离的最大值,如果超过这个最大值则点不会被划分到该直线。有默认值0

示例代码

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>using namespace std;
using namespace cv;int main()
{Mat srcImage;srcImage = imread("building.jpg");        //加载图像文件//判断图像是否加载成功if(srcImage.empty()){cout << "图像加载失败!" << endl;return -1;}elsecout << "图像加载成功!" << endl << endl;namedWindow("原图像", WINDOW_AUTOSIZE);imshow("原图像", srcImage);Mat midImage, dstImage;Canny(srcImage, midImage, 50, 200, 3);        //首先对图像进行边缘检测cvtColor(midImage, dstImage, COLOR_GRAY2BGR);//进行霍夫变换vector<Vec4i> lines;HoughLinesP(midImage, lines, 1, CV_PI/180, 200, 30, 10);for(size_t i = 0; i < lines.size(); i++){line(dstImage, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]),Scalar(0, 0, 255), 1, 8);}namedWindow("霍夫线变换", WINDOW_AUTOSIZE);imshow("霍夫线变换", dstImage);waitKey(0);return 0;
}

运行结果

3霍夫圆变换

霍夫圆变换的基本原理和霍夫线变换类似,值时点对应的二维极径极角空间被三维的圆心点x, y还有半径r空间取代。对直线来说,一条直线能由参数极径极角(r, θ),而对圆来说,我们需要三个参数来表示一个圆,现在原图像的边缘图像的任意点对应的经过这个点的所有可能圆是在三维空间由下面这三个参数来表示了,对应一条三维空间的曲线。
C:(Xcenter, Ycenter, r)
这里的(Xcenter, Ycenter)表示圆心的为之而r表示半径
与二维的霍夫线变换同样的道理,对于多个边缘点越多这些点对应的三维空间曲线相交于一点那么他们经过共同圆的点就越多,类似的我们也就可以用同样的阈值的方法来判断一个圆是否被检测到,这就是标准霍夫圆变换的原理,但也正是在三维空间计算梁大大增加的原因,标准霍夫圆变化很难被应用到实际中。
出于对运算效率的考虑,opencv实现的是一个比标准霍夫圆变换更为灵活的检测方法:霍夫梯度法,也叫2-1霍夫变换(21HT),它的原理依据是圆心一定在圆上的每个点的模向量上,这些圆上点模向量的焦点就是圆心,霍夫梯度法的第一部就是找到这些圆心,这样三维的累加平面就又转化为二维累加平面。第二步根据所有候选中心的边缘非0像素对其的支持程度来确定半径。21HT方法最早在ILLingworth的论文The Adaptive Hough Transform中提出并详细描述,也可参照Yuen在1990年发表的A Comparative Study of Hough Transform Methods for Circle Finding, Bradski的《学习OpenCV》对opencv中具体算法实现有详细描述并讨论霍夫梯度法的局限性。

opencv中提供了HoughCircles()函数来实现霍夫圆变换。其函数原型如下:

void cv::HoughCircles   (   InputArray      image,OutputArray     circles,int     method,double      dp,double      minDist,double      param1 = 100,double      param2 = 100,int     minRadius = 0,int     maxRadius = 0 )   

参数解释

  • .image: 输入图像为8位单通道灰度图
  • .circles: 检测到圆的输出矢量,每个矢量都是三个浮点元素构成(x,y,radius)
  • .method: 检测方法,可以查看HoughModes查看具体细节,但目前只有HOUGH_GRADIENT(霍夫梯度)一种方法可以使用。
  • .dp: 用来检测圆心的累加器图像的分辨率与输入图像之比的倒数,且此参数允许创建一个比输入图像分辨率低的累加器。例如,如果dp=1,累加器和输入图像具有相同的分辨率,如果dp=2累加器便有输入图像一半那么大的宽度和高度。
  • .minDist: 霍夫检测到的圆的圆心之间的最小距离,即让算法能明显区分的两个不同圆之间的最小距离。这个参数如果太小的话,多个相邻的圆可能被错误的检测成了一个重合的圆。繁殖这个参数设置太大,某些圆就不能被检测出来了。也就是超过这个距离就是两个圆,否则是一个圆。
  • .param1: 指定检测方法的第一个参数,当前可用方法是HOUGH_GRADIENT,它表示传递给Canny边缘检测算子的高阈值(低阈值是高阈值的一半),有默认值100
  • param2: 指定检测方法的第二个参数,对于HOUGH_GRADIENT方法,它表示在检测阶段圆心的累加器阈值。它越小就越可以检测到更多根本不存在的圆,而它越大的话能通过检测的圆就更加接近完美的圆形了。有默认值100
  • .minRadius: 圆的最小半径
  • .maxRadius: 圆的最大半径

示例代码

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>using namespace std;
using namespace cv;int minDist;
int param1;
int param2;
String windowName = "霍夫圆检测";
vector<Vec3f> circles;              //用来存放检测到的圆参数矢量int main()
{Mat srcImage,grayImage;srcImage = imread("ball.jpg");//判断文件是否加载成功if(srcImage.empty()){cout << "图像加载失败!" << endl;return -1;}elsecout << "图像加载成功!" << endl << endl;//初始化参数minDist = srcImage.rows/8;param1 = 100;param2 = 100;namedWindow(windowName, WINDOW_AUTOSIZE);cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);imshow("灰度图", grayImage);GaussianBlur(grayImage, grayImage, Size(3, 3), 2, 2);       //高斯滤波//霍夫圆检测HoughCircles(grayImage, circles, CV_HOUGH_GRADIENT, 1, minDist, param1, param2, 0, 0);//绘制检测到的圆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(srcImage, center, 3, Scalar(0, 0, 255), -1, 8, 0);circle(srcImage, center, radius, Scalar(0, 0, 255), 3, 8, 0);}imshow(windowName, srcImage);waitKey(0);return 0;
}

运行结果

opencv学习(三十三)之霍夫变换相关推荐

  1. OpenCV学习(二十三) :模板匹配:matchTemplate(),minMaxLoc()

    OpenCV学习(二十三) :模板匹配:matchTemplate() 1.概述 模板匹配是一种最原始.最基本的模式识别方法,研究某一特定对象物的图案位于图像的什么地方,进而识别对象物,这就是一个匹配 ...

  2. OpenCV学习三:Mat类详解

    目标 我们有多种方法可以获得从现实世界的数字图像:数码相机.扫描仪.计算机体层摄影或磁共振成像就是其中的几种.在每种情况下我们(人类)看到了什么是图像.但是,转换图像到我们的数字设备时我们的记录是图像 ...

  3. opencv学习(三十五)之仿射变换warpAffine

    1.仿射变换介绍 仿射变换是指在向量空间中进行一次线性变换(乘以一个矩阵)并加上一个平移(加上一个向量),变换为另一个向量空间的过程.在有限维的情况下,每个仿射变换可以由一个矩阵A和一个向量b给出,它 ...

  4. java aio socket_java核心学习(三十三) 网络编程---AIO实现异步Socket通信

    AIO需要操作系统的支持,在linux内核2.6版本中加入了对真正异步IO的支持,java从jdk1.7开始支持AIO 核心类有AsynchronousSocketChannel .Asynchron ...

  5. Java多线程学习三十三:Future 的主要功能是什么?

    Future 类 Future 的作用 Future 最主要的作用是,比如当做一定运算的时候,运算过程可能比较耗时,有时会去查数据库,或是繁重的计算,比如压缩.加密等,在这种情况下,如果我们一直在原地 ...

  6. opencv学习(三十九)之反向投影calcBackProject()

    1.概述 反向投影是一种记录给定图像中的像素点如何适应直方图模型像素分布的方式,简单来讲,反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的特征.反向投影在某一位置的值就是原图对 ...

  7. OpenCV学习第十三篇:提取水平和垂直线(去除干扰线)

    1.结构元素 可以是任意形状的结构元素:矩形,圆,直线,磁盘形状,砖石形状等 2.提取步骤 输入图像彩色图像imread 转换为灰度图像cvtColor 转换为二值图像adaptiveThreshol ...

  8. OpenCV学习三十四:watershed 分水岭算法

    1. watershed void watershed( InputArray image, InputOutputArray markers ); 第一个参数 image,必须是一个8bit 3通道 ...

  9. opencv学习(四十三)之图像的矩moments()

    1.概述 图像识别的一个核心问题是图像的特征提取,简单描述即为用一组简单的数据(数据描述量)来描述整个图像,这组数据月简单越有代表性越好.良好的特征不受光线.噪点.几何形变的干扰,图像识别技术的发展中 ...

最新文章

  1. Amazon AWS云计算服务平台概述
  2. 数学之旅-不动点定理
  3. Cordova 本地项目创建方法
  4. php检测非法字符的一种方法
  5. Visual Studio 2017 ASP.NET Core开发
  6. 关于CaciiEZ端口流量阀值报警的设置
  7. answer的汉语_大概是几乎能满足你们所有要求的两所学校(汉语言文字学、语言学及应用语言学择校攻略)...
  8. 开发者硬核福利!极光可信数据云来了
  9. idea java代码格式化_IDEA java 代码格式化统一
  10. 安装教程之JDK下载与安装_更新2022
  11. vs2015好看的字体_【Vs2015】 常用字体的设置
  12. 算法设计与分析第一章习题解答与学习指导(第2版)屈婉婷 刘田 张立昂 王捍贫编著 清华大学出版社
  13. Crystal Reports - 根据模板导出PDF文件
  14. 经典C语言编程100例——题目+答案代码(1-10)
  15. 蚂蚁小程序--自学笔记
  16. css手册.chm + W3CSchool.chm下载
  17. 服务器保密系统,泛微OA系统secWall保密方案之一:服务器端部署
  18. Android超人气系列动态壁纸下载(免费)
  19. 此战成硕,我成功上岸西南交通大学了~~~
  20. java hbase 批量查询数据_java Hbase 批量读取

热门文章

  1. unity UGUI 优化
  2. [深度学习] 不平衡样本的处理
  3. 加特兰 77GHz CMOS 毫米波雷达芯片从研发到量产的背后故事...
  4. 实验5 IP地址分配
  5. 利用java实现数据库数据随机生成
  6. 发光二极管的发光原理
  7. 接上篇(解决float导致塌陷问题)之clear:both失效
  8. Linux拓展之查找指定目录下的最大文件
  9. Py测开《多态和鸭子类型的区别》
  10. 推荐一个vue的组件分享网站--轮子工厂