7.2 霍夫变换

7.2.1 概述

1.特征提取技术,运用两个坐标空间之间的变换将在一个空间中具有相同形状的曲线或直线映射到另一个坐标空间的一个点上形成峰值,从而把检测任意形状的问题转化为统计峰值问题,用于检测直线、曲线、圆、椭圆等。
2.分类:(1)霍夫线变换(2)霍夫圆变换

7.2.2 霍夫线变换

1.原理:
(1)直线在坐标空间的表示:
  1)笛卡尔坐标系:斜率和截距(m,b)表示
  2)极坐标系:极径和极角(r,θ)
  霍夫变换采用极坐标系表示直线:
                
  即:
                 
(2)对于通过点(x0,y0)的一族直线,可表示为:
                
(3)对于给定点(x0,y0),在极坐标对极径极角平面绘出所有通过它的直线,得到一条正弦曲线,如给定点(8,6):
           
(4)对图像中所有点绘制正弦曲线,如果两个不同点曲线在平面θ-r相交,意味着它们通过同一条直线,如点(9,4)和点(12,3):
           
(5)上述说明,一条直线能够通过平面θ-r寻找交于一点的曲线数量来检测,而越多曲线交于一点表示直线由更多的点组成,可以通过设置直线上点的阈值来定义多少条曲线交于一点,才认为检测到了一条直线
(6)所以,霍夫变换追踪图像中每个点对应曲线间的交点,如果交于一点的曲线数量超过阈值,可认为这个交点代表的参数对(θ,r)在原图像中为一条直线
2.分类:
(1)标准霍夫变换(Standard Hough Transform,SHT),HoughLines函数调用
(2)多尺度霍夫变换(Multi-Scale Hough Transform,MSHT):SHT在多尺度下的变种,HoughLines调用
(3)累计概率霍夫变换(Progressive Probabilistic Hough Transform,PPHT):SHT的一个改进,在一定范围内进行霍夫变换,计算单独线段的方向及范围,从而减少计算量,缩短计算时间,HoughLinesP调用

7.2.2.1 标准/多尺度霍夫变换:HoughLines()函数

1.作用:可以找出采用标准霍夫变换的二值图像线条
2.函数原型:

void HoughLines(InputArray image, OuputArray lines, double rho, double theta, int threshold, double srn=0,double stn=0)

3.参数说明:
(1)输入图像,8位单通道二进制图像
(2)检测到线条的输出矢量,一条线由两个元素矢量(ρ,θ)表示,ρ是距坐标原点(0,0)距离,θ是弧度线条旋转角度
(3)以像素为单位的距离精度,直线搜索时的进步尺寸单位半径
(4)以弧度为单位的角度精度,直线搜索时的进步尺寸单位角度
(5)累加平面的阈值参数,识别某部分为图中一条直线时在累加平面中必须达到的值
(6)多尺度霍夫变换中第三个参数rho的除数距离,默认值0,粗略的累加器进步尺寸直接为rho,精确的累加器进步尺寸为rho/srn
(7)多尺度霍夫变换中第四个参数theta的除数距离,默认值0,srn和stn同时为0表示使用SHT,否则两参数都应为正数
4.调用示例:

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{//【1】载入原图Mat srcImage = imread("1.png");Mat midImage, dstImage;//【2】进行边缘检测,将HoughLines函数输入图像处理为边缘二值图Canny(srcImage, midImage, 50, 200, 3);//【3】转换边缘检测后的边缘二值图像为灰度图cvtColor(midImage, dstImage, CV_GRAY2BGR);//【4】进行霍夫线变换vector<Vec2f>lines;//定义一个矢量结构lines用于存放得到的线性矢量集合HoughLines(midImage, lines, 1, CV_PI / 180, 150, 0, 0);//【5】依次在灰度图中绘制出每条线段for (size_t i = 0; i < lines.size(); i++){float rho = lines[i][0], 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(55, 100, 195), 1, LINE_AA);}//【5】显示原始图imshow("【原始图】", srcImage);//【6】边缘检测后的图imshow("【边缘检测效果图】", midImage);//【7】显示效果图imshow("【霍夫线变换效果图】", dstImage);waitKey(0);return 0;
}

运行效果:

7.2.2.2 累计概率霍夫变换:HoughLinesP()函数

1.函数原型:

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

2.参数说明:
(1)输入图像,8位单通道二进制图像
(2)检测到线条的输出矢量,一条线由4个元素矢量(x_1,y_1,x_2,y_2)表示
(3)以像素为单位的距离精度,直线搜索时的进步尺寸单位半径
(4)以弧度为单位的角度精度,直线搜索时的进步尺寸单位角度
(5)累加平面的阈值参数,识别某部分为图中一条直线时在累加平面中必须达到的值
(6)表示最低线段的长度,默认值0,比这个设定参数短的线段不被显现
(7)允许将同一行点与点之间连接起来的最大距离,默认值0
3.调用示例:

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{//【1】载入原始图和Mat变量定义   Mat srcImage = imread("1.png");Mat midImage, dstImage;//【2】进行边缘检测,将HoughLines函数输入图像处理为边缘二值图Canny(srcImage, midImage, 50, 200, 3);//【3】转换边缘检测后的边缘二值图像为灰度图cvtColor(midImage, dstImage, CV_GRAY2BGR);//【4】进行累计概率霍夫线变换vector<Vec4i>lines;//定义一个矢量结构lines用于存放得到的线段矢量集合HoughLinesP(midImage, lines, 1, CV_PI / 180, 80, 50, 10);//【5】依次在图中绘制出每条线段for (size_t i = 0; i < lines.size(); i++){Vec4i l = lines[i];line(dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186, 88, 255), 1, CV_AA);}//【6】显示原始图  imshow("【原始图】", srcImage);//【7】边缘检测后的图 imshow("【边缘检测效果图】", midImage);//【8】显示效果图  imshow("【累计概率霍夫变换效果图】", dstImage);waitKey(0);return 0;
}

运行效果:

7.2.3 霍夫圆变换

1.与霍夫线变换类似,只是点对应的二维极径极角空间被三维的圆心点x,y,和半径r空间取代,用三个参数表示圆:
                 
2.方法:霍夫梯度法
(1)对图像进行边缘检测
(2)对边缘图像中的每一个非零点,考虑其局部梯度,即用Sobel()函数计算x,y方向的Sobel一阶导数得到的梯度
(3)利用得到的梯度,由斜率(从一个指定的最小值到指定的最大值的距离)指定的直线上的每一个点都在累加器中被累加
(4)标记边缘图像中每一个非0像素位置
(5)从二维累加器中这些点中选择大于给定阈值且大于其所有近邻的候选中心,按累加值降序排列
(6)对每个中心,考虑所有非0像素,按照像素与中心距离排序,从最大半径的最小距离算起,选择非0像素最支持的一条半径
(7)如果一个中心收到边缘图像非0像素最充分的支持,并且到前期被选择的中心有足够的距离,它就会被保留
3.霍夫梯度法的缺点:
(1)Sobel导数计算局部梯度,假设它可以视作一条局部切线,数值不稳定,可能产生噪声
(2)边缘图像中的整个非0像素集被看作每个中心的候选部分,如果把累加器阈值设置偏低,算法费时
(3)过于相近的中心不会被保留,同心圆或过于相似圆保留最大的圆,极端
4.函数:HoughCircles()函数
5.函数原型:

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

6.参数说明:
(1)输入图像,8位灰度单通道图像
(2)检测到的圆输出矢量,每个矢量包含3个元素的浮点矢量(x,y,radius)
(3)使用的检测方法,HOUGH_GRADIENT
(4)用来检测圆心的累加器图像的分辨率与输入图像之比的倒数,允许创建一个比输入图像分辨率低的累加器,如果dp=1累加器和输入图像具有相同的分辨率,如果dp=2累加器具有输入图像一半的宽度和高度
(5)霍夫变换检测到的圆的圆心之间的最小距离,设置太小多个相邻圆可能检测为一个,太大某些圆不能被检测出来
(6)第三个参数设置的检测方法对应的参数,即霍夫梯度法,表示传递给canny边缘检测算子的高阈值,低阈值为高阈值的一半,默认100
(7)第三个参数设置的检测方法对应的参数,即霍夫梯度法,表示在检测阶段圆心的累加器阈值。越小越可以检测到更多不存在的圆,越大能通过检测的圆越接近完美圆形,默认100
(8)圆半径的最小值,默认0
(9)圆半径的最大值,默认0
7.调用示例:

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{//【1】载入原始图和Mat变量定义   Mat srcImage = imread("1.jpg");Mat midImage, dstImage;//【2】显示原始图imshow("【原始图】", srcImage);//【3】转为灰度图,进行图像平滑cvtColor(srcImage, midImage, CV_BGR2GRAY);GaussianBlur(midImage, midImage, Size(9, 9), 2, 2);//【4】进行霍夫圆变换vector<Vec3f> circles;HoughCircles(midImage, circles, CV_HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);//【5】依次在图中绘制出圆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, 255, 0), -1, 8, 0);//绘制圆轮廓circle(srcImage, center, radius, Scalar(155, 50, 255), 3, 8, 0);}//【6】显示效果图  imshow("【效果图】", srcImage);waitKey(0);return 0;
}

运行效果:

7.2.4 霍夫变换综合示例

/*
效果:
滚动条改变阈值threshold,动态控制霍夫线变换检测的线条多少
*/
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;//全局变量声明
Mat g_srcImage, g_dstImage, g_midImage;//原始图、中间图和效果图
vector<Vec4i> g_lines;  //定义一个矢量结构g_lines用于存放得到的线段矢量集合
int g_nthreshold = 100; //变量接收的TrackBar位置参数//全局函数声明
static void on_HoughLinesP(int, void*);
static void ShowHelpText();int main()
{//改变console字体颜色system("color 3F");ShowHelpText();//载入原始图和Mat变量定义   Mat g_srcImage = imread("1.jpg");//显示原始图  imshow("【原始图】", g_srcImage);//创建滚动条namedWindow("【效果图】", 1);createTrackbar("值", "【效果图】", &g_nthreshold, 150, on_HoughLinesP);//进行边缘检测和转化为灰度图Canny(g_srcImage, g_midImage, 50, 200, 3);    //进行一次canny边缘检测cvtColor(g_midImage, g_dstImage, CV_GRAY2BGR);//转化边缘检测后的图为灰度图//调用一次回调函数,调用一次HoughLinesP函数on_HoughLinesP(g_nthreshold, 0);waitKey(0);return 0;
}//累计概率霍夫变换回调函数
static void on_HoughLinesP(int, void*)
{//定义局部变量储存全局变量Mat dstImage = g_dstImage.clone();Mat midImage = g_midImage.clone();//调用HoughLinesP函数vector<Vec4i> mylines;HoughLinesP(midImage, mylines, 1, CV_PI / 180, g_nthreshold + 1, 50, 10);//循环遍历绘制每一条线段for (size_t i = 0; i < mylines.size(); i++){Vec4i l = mylines[i];line(dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(23, 180, 55), 1, CV_AA);}//显示图像imshow("【效果图】", dstImage);
}//ShowHelpText( )函数
static void ShowHelpText()
{//输出一些帮助信息printf("\n\n\n\t请调整滚动条观察图像效果~\n\n");
}

运行效果:

《OpenCV3编程入门》学习笔记7 图像变换(二 )霍夫变换相关推荐

  1. 原创 OpenCV3编程入门 学习笔记(总)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_36163358/article/ ...

  2. OpenCV3编程入门 学习笔记(总)

    OpenCV3编程入门 学习笔记 2018.12.12-2018.12.29 此博客为在看过毛星云版<OpenCV3编程入门>后所总结的一本笔记,可供复习使用. 文章目录 OpenCV3编 ...

  3. Opencv3编程入门学习笔记(五)之通道分离(split)与合并(merge)

    若要对Opencv中(BGR)颜色通道进行单一处理,那必然会涉及到通道分离(split)与合并(merge).那么本篇博客笔者记录了两个方法的使用方法和案例.案例来源于<Opencv3编程入门学 ...

  4. Opencv3编程入门学习笔记(二)之显式创建Mat对象

    以下总结是基于<Opencv3编程入门>一书4.1节总结的内容进行验证与总结,验证环境均为Windows10 ---VS2013 C++环境,验证Opencv3.0提供的开发包. 1. 方 ...

  5. 【OpenCV3编程入门学习笔记】——第1章 邂逅OpenCV

    邂逅OpenCV 文章目录 邂逅OpenCV 前言 1.1 OpenCV周边概念认知 1.1.1 图像处理.计算机视觉与OpenCV 1.1.2 OpenCV概述 1.1.3 起源及发展 1.1.4 ...

  6. Opencv3编程入门学习笔记(三)之访问图像像素的三种方法

    访问图像像素的三种方法:指针访问,迭代器访问,动态地址访问.访问最快的为指针访问,以下算法在几毫秒,但指针访问容易造成内存泄漏:其次为迭代器访问:最后为动态地址访问. 以下程序是根据<OpenC ...

  7. 【OpenCV3编程入门学习笔记】——第3章 HighGUI图形用户界面初步

    文章目录 前言 3.1 图形的载入.显示和输出到文件 3.1.1 OpenCV的命名空间 3.1.2 Mat类简析 3.1.3 图像的载入与显示概述 3.1.4 图像的载入:imread()函数 3. ...

  8. Opencv3编程入门学习笔记(四)之split通道分离Debug过程中0xC0000005内存访问冲突问题

    这是笔者学习<Opencv3编程入门>的第四篇博客,这篇博客主要是解决在Windows系统下VS 2013中Debug含有split分离通道色彩函数时报出的0xC0000005内存访问冲突 ...

  9. 汇编入门学习笔记 (十二)—— int指令、port

    疯狂的暑假学习之  汇编入门学习笔记 (十二)--  int指令.port 參考: <汇编语言> 王爽 第13.14章 一.int指令 1. int指令引发的中断 int n指令,相当于引 ...

  10. 01.Java 编程入门学习笔记20210307

    Java 编程入门学习笔记-day01 第0章:编程入门 1.计算机的概述 计算机 = 硬件 + 软件 1.1硬件:冯诺依曼体系 CPU: CPU的衡量标准:速度的计量单位是赫兹(Hz),1Hz相当于 ...

最新文章

  1. 15.Node.js REPL(交互式解释器)
  2. Build path -No action available/classpath .project
  3. linux eth0 proxy arp,在interface vlan下敲no ip proxy-arp什么意思
  4. 第 14 章 程序员常用 10 种算法
  5. 程序员必知3大查找(转)
  6. Vue 电商管理系统
  7. 互联网专用计算机屏保,18个Windows 98屏保,简直怀念!
  8. 使用HTML实现用户登录界面
  9. Vs2010激活 系统延长期限
  10. 【六袆 - Java】跟WebService说Hola;入门WebService;
  11. 小米手机开机自启动软件及定时开关机
  12. 抖音自媒体上热门的诀窍,高效蹭实时热点的4个技巧
  13. 你的走路姿势正确吗?步态不对牵连多种疾病
  14. 苹果Arcade订阅常见问题
  15. TimeStamp日期类型转化成json
  16. 如何修复Outlook已发送邮件丢失的问题
  17. 羽绒服行业深度报告:品牌制胜,羽绒服行业如何实现升级之路?-20210104
  18. Kubeadm初始化报错
  19. Netty简单实现客户端与服务端收发消息
  20. 第一次作业 对软件工程的疑问

热门文章

  1. 安装win下的Anaconda ----针对python3.6.4版本
  2. 基于BERT预训练的中文命名实体识别TensorFlow实现
  3. 缓存击穿、缓存穿透、缓存雪崩
  4. TensorRT优化方案图例
  5. ContentProvider是如何实现数据共享的
  6. Python:Downloader Middlewares
  7. Django 视图URLconf3.1
  8. pip install numpy/pandas时报错的解决方法
  9. android.view.InflateException: Binary XML file line #8: Binary XML file line #8: Error inflating cl
  10. 2018年爱奇艺校招笔试