我们如何在图像中快速识别出其中的圆和直线?一个非常有效的方法就是霍夫变换,它是图像中识别各种几何形状的基本算法之一。

霍夫线变换

霍夫线变换是一种在图像中寻找直线的方法。OpenCV中支持三种霍夫线变换,分别是标准霍夫线变换、多尺度霍夫线变换、累计概率霍夫线变换。

在OpenCV中可以调用函数HoughLines来调用标准霍夫线变换和多尺度霍夫线变换。HoughLinesP函数用于调用累积概率霍夫线变换。

我们都知道,二维坐标轴上表示一条直线的方程式y = a*x + b,我们想求出一条直线就得想方设法求出其中的a和b的值。如果用极坐标来表示就是

theta就是直线与水平线所成的角度,而rho就是圆的半径(也可以理解为原点到直线的距离),同样地,这两个参数也是表征一条直线的重要参数,确定他们俩了,也就确定一条直线了。正如下图所示。

在OpenCV里,我们只需调用HoughLines就是可以得到表征一条直线的这两个参数值!

HoughLines用法

#include <iostream>
#include <opencv2\opencv.hpp>
#include <opencv2\imgproc\imgproc.hpp> using namespace cv;
using namespace std; int main()
{
Mat srcImage = imread("4.jpg");
imshow("Src Pic", srcImage); Mat midImage, dstImage;
//边缘检测
Canny(srcImage, midImage, 50, 200, 3);
//灰度化
cvtColor(midImage, dstImage, CV_GRAY2BGR);
// 定义矢量结构存放检测出来的直线
vector<Vec2f> lines;
//通过这个函数,我们就可以得到检测出来的直线集合了
HoughLines(midImage, lines, 1, CV_PI / 180, 150, 0, 0);
//这里注意第五个参数,表示阈值,阈值越大,表明检测的越精准,速度越快,得到的直线越少(得到的直线都是很有把握的直线)
//这里得到的lines是包含rho和theta的,而不包括直线上的点,所以下面需要根据得到的rho和theta来建立一条直线 //依次画出每条线段
for (size_t i = 0; i < lines.size(); i++)
{
float rho = lines[i][0]; //就是圆的半径r
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(55, 100, 195), 1, LINE_AA); //Scalar函数用于调节线段颜色,就是你想检测到的线段显示的是什么颜色 imshow("边缘检测后的图", midImage);
imshow("最终效果图", dstImage);
}
waitKey();
return 0;
}

原图

阈值我设为250,看看直线检测的效果。你会发现,怎么图中一些很明显的的直线都没检测出来啊?原因是,我们阈值写的有点高了,只有那些有足够的把握认为是直线的直线才可能检测出来。

然后我把阈值改为150,直线检测效果就变成这样子了。显然多了很多直线,这是我们把我们的要求降低了,把那些“可能是直线”的直线都当做是直线了。所以,阈值的选择很重要,就看你是要精确查找还是模糊查找了。

后来我又加了一句打印进去,想看看角度的单位是什么

	cout << "line " << i << ": " << "rho:" << rho << " theta:" << theta << endl;

可以看到,角度theta用的单位不是我们所说的度数(70度、80度),而是数学上的π/2,π/3。

要想转为我们所说的度数,自己写个转换吧

float angle = theta / CV_PI * 180;

可以看出,转换后的角度范围就是我们想要的度数!值得注意的是,rho表示离坐标原点(就是图片左上角的点)的距离,theta是直线的旋转角度(0度表示垂直线,90度表示水平线)。

HoughLinesP用法

此函数在HoughLines的基础上在末尾加了一个代表Probabilistic(概率)的P,表明使用的是累计概率变换。

#include <iostream>
#include <opencv2\opencv.hpp>
#include <opencv2\imgproc\imgproc.hpp> using namespace cv;
using namespace std; int main()
{
Mat srcImage = imread("2.jpg");
imshow("Src Pic", srcImage); Mat midImage, dstImage; Canny(srcImage, midImage, 50, 200, 3);
cvtColor(midImage, dstImage, CV_GRAY2BGR); vector<Vec4i> lines;
//与HoughLines不同的是,HoughLinesP得到lines的是含有直线上点的坐标的,所以下面进行划线时就不再需要自己求出两个点来确定唯一的直线了
HoughLinesP(midImage, lines, 1, CV_PI / 180, 80, 50, 10);//注意第五个参数,为阈值 //依次画出每条线段
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, LINE_AA); //Scalar函数用于调节线段颜色 imshow("边缘检测后的图", midImage);
imshow("最终效果图", dstImage);
}
waitKey();
return 0;
}

貌似效果还不错。

霍夫圆变换

刚刚的霍夫变换是检测直线的,如果我们想检测圆形,那该怎么办?那就用霍夫圆变换!用法也大同小异。

#include <iostream>
#include <opencv2\opencv.hpp>
#include <opencv2\imgproc\imgproc.hpp> using namespace cv;
using namespace std; int main()
{
Mat srcImage = imread("test5.jpg");
Mat midImage, dstImage;//临时变量和目标图的定义 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, 150, 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;
}

可以看到,有一些圆没有检测出来,同时还有一些不是圆形的确有误以为是圆形了,说明阈值选择不是很妥当。

另外提一点,霍夫圆变换的检测速度真的慢,显然进行圆检测的计算量还真不少!

OpenCV探索之路(七):霍夫变换的更多相关文章

  1. OpenCV探索之路(二十四)图像拼接和图像融合技术

    图像拼接在实际的应用场景很广,比如无人机航拍,遥感图像等等,图像拼接是进一步做图像理解基础步骤,拼接效果的好坏直接影响接下来的工作,所以一个好的图像拼接算法非常重要. 再举一个身边的例子吧,你用你的手 ...

  2. OpenCV探索之路(十六):图像矫正技术深入探讨

    刚进入实验室导师就交给我一个任务,就是让我设计算法给图像进行矫正.哎呀,我不太会图像这块啊,不过还是接下来了,硬着头皮开干吧! 那什么是图像的矫正呢?举个例子就好明白了. 我的好朋友小明给我拍了这几张 ...

  3. OpenCV探索之路(二十二):制作一个类“全能扫描王”的简易扫描软件

    相信很多人手机里都装了个"扫描全能王"APP,平时可以用它来可以扫描一些证件.文本,确实很好用,第一次用的时候确实感觉功能很强大啊算法很牛逼啊.但是仔细一想,其实这些实现起来也是很 ...

  4. C++ Opencv HoughLines()用霍夫变换在二元图像中寻线

    一.霍夫变换简介 参考http://homepages.inf.ed.ac.uk/rbf/HIPR2/hough.htm 二.HoughLines()函数详解 该函数接受的输入矩阵只能是8位单通道的二 ...

  5. opencv学习笔记霍夫变换——直线检测

    参考大佬博文:blog.csdn.net/jia20003/article/details/7724530 lps-683.iteye.com/blog/2254368 openCV里有两个函数(比较 ...

  6. 【学习opencv第七篇】图像的阈值化

    图像阈值化的基本思想是,给定一个数组和一个阈值,然后根据数组中每个元素是低于还是高于阈值而进行一些处理. cvThreshold()函数如下: double cvThreshold( CvArr* s ...

  7. opencv探索之路(一):win10 X64+VS2015+opencv3.10安装教程

    我的电脑64位Win10系统,现在利用VS2015安装opencv3.10.安装之路颇为艰辛,从一开始的VS2015的安装,到opencv的安装,都充满挑战,历经千辛万苦终于把opencv开发环境搭建 ...

  8. OpenCV探索之路(三):滤波操作

    滤波处理分为两大类:线性滤波和非线性滤波.OpenCV里有这些滤波的函数,使用起来非常方便,现在简单介绍其使用方法. 线性滤波:方框滤波.均值滤波.高斯滤波 方框滤波 #include<open ...

  9. OpenCV探索之路(五):图片缩放和图像金字塔

    对图像进行缩放的最简单方法当然是调用resize函数啦! resize函数可以将源图像精确地转化为指定尺寸的目标图像. 要缩小图像,一般推荐使用CV_INETR_AREA来插值:若要放大图像,推荐使用 ...

随机推荐

  1. 老李分享:Android -自动化埋点 1

    老李分享:Android -自动化埋点   当我们开发一款Android应用上线后,希望能收集一些用户操作的行为数据,比如用户在某个页面点击了多少次,在某个控件被点击了多少次,在某个页面停 留了多少时 ...

  2. 手机自动化测试:appium源码分析之bootstrap十三

    手机自动化测试:appium源码分析之bootstrap十三   poptest(www.poptest.cn)是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开 ...

  3. 浏览器访问php脚本通过sendmail用mail函数发送邮件

    前几天做项目遇到这样的一个问题:当某一个结点下有新的文章发表的时候,以邮件的形式通知该结点下的所有用户.这就需要用到邮件发送的功能. 因为项目是php语言做的,所以最简单的方法就是使用php自带的函数 ...

  4. JDBC基础学习(六)—数据库连接池

    一.数据库连接池介绍 1.数据库连接池的缘由      对于一个简单的数据库应用,由于对于数据库的访问不是很频繁.这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什 ...

  5. 《c#入门经典第五版》简介及pdf电子书网盘下载地址(收藏)

    <C#入门经典(第5版)>全面讲解C# 2010和.net架构编程知识,为您编写卓越C# 2010程序奠定坚实基础.C#入门经典系列是屡获殊荣的C#名著和超级畅销书.最新版的<C#入 ...

  6. AngularJS学习笔记4

    9.AngularJS  XMLHttpRequest $http 是 AngularJS 中的一个核心服务,用于读取远程服务器的数据. <div ng-app="myApp" ...

  7. spring之注解

    1.@Autowired 可以对成员变量.方法和构造函数进行自动配置(根据类型进行自动装配) public class UserImpl implements User { @Autowired pr ...

  8. iOS原生地图与高德地图的使用

    原生地图 1.什么是LBS LBS: 基于位置的服务 Location Based Service 实际应用:大众点评,陌陌,微信,美团等需要用到地图或定位的App 2.定位方式 1.GPS定位 2. ...

  9. java获得路径的多种方式

    本文讲解java语言中获得运行时路径的多种方式,包括java项目.java web项目.jar.weblogic等多种场景. 一.this.getClass().getClassLoader().ge ...

  10. C# TreeGridView 实现进程列表

    效果如图 0x01 获取进程列表,使用Win32Api规避"拒绝访问"异常 public List<AppProcess> GetAppProcesses() { In ...