0
点赞
收藏
分享

微信扫一扫

【opencv学习笔记】021之霍夫直线变换原理详解


目录

​​一、前言​​

​​二、霍夫变换​​

​​1、霍夫变换是个啥​​

​​2、常用霍夫变换​​

​​三、霍夫直线变换​​

​​1、讲解​​

​​2、API​​

​​1.HoughLines​​

​​2.HoughLinesP​​

​​3、代码展示​​

​​4、执行结果​​

一、前言

终于更新到霍夫直线变换了,跟以前写的博客成功接轨。opencv基础博客也即将更新完毕,感谢大家的支持,我们要再接再厉呀!

如果想看其他有关于OpenCV学习方法介绍、学习教程、代码实战、常见报错及解决方案等相关内容,可以直接看我的OpenCV分类:

 

二、霍夫变换

1、霍夫变换是个啥

我们先来了解一下霍夫变换是个啥

霍夫变换是一种特征检测(feature extraction),被广泛应用在图像分析(image analysis)、计算机视觉(computer vision)以及数位影像处理(digital image processing)。

霍夫变换是用来辨别找出物件中的特征,其流程大致如下:

给定一个物件、要辨别的形状的种类,算法会在参数空间(parameter space)中执行投票来决定物体的形状,而这是由累加空间(accumulator space)里的局部最大值(local maximum)来决定。

 

2、常用霍夫变换

我们会经常使用到如下两个霍夫变换:

1.霍夫直线变换:在图像中寻找直线

2.霍夫圆变换:在图像中寻找圆。

这个博客,我们一起来了解一下啥是霍夫直线变换,。如果你想了解霍夫圆变换,请转移到:

【opencv学习笔记】022之霍夫圆变换

 

三、霍夫直线变换

1、讲解

上面我们知道霍夫直线变换,就是用来检测直线的,那怎么知道一条线是直线呢?

【opencv学习笔记】021之霍夫直线变换原理详解_霍夫变换

假设我们有上图这个红色的直线,大家看到这个θ和r,学过极坐标的同学应该就能知道了,我们要用极坐标来表示直线了。

对于一条直线来说,我们首先要知道它的平面直角坐标表示(只考虑二维平面):

【opencv学习笔记】021之霍夫直线变换原理详解_double类型_02

而对于上图,我们能知道:

【opencv学习笔记】021之霍夫直线变换原理详解_霍夫变换_03

根据上面的公式,我们能够推导出如下公式:

【opencv学习笔记】021之霍夫直线变换原理详解_hough变换_04

推导过程可以如下:

【opencv学习笔记】021之霍夫直线变换原理详解_霍夫直线变换_05

得到这个公式,有什么作用呢?

我们知道x和y是直线上的点,我们为了方便讲解,我们取一条直线来说明:

【opencv学习笔记】021之霍夫直线变换原理详解_double类型_06

对于上面这条直线,有如下五个点是在直线上的:

【opencv学习笔记】021之霍夫直线变换原理详解_double类型_07

所以我们可以得到五条直线:

【opencv学习笔记】021之霍夫直线变换原理详解_霍夫直线变换_08

如果我们以θ为横坐标,r为纵坐标,当我们把这五条直线画在同一个坐标系中,我们能得到下面这幅图:

【opencv学习笔记】021之霍夫直线变换原理详解_霍夫直线变换_09

我们发现,这五条直线交于同一点,这就是直线有的特点,我们就通过这个特点,将所有的直线累加,那交点处因为是所有直线的累加,其像素值一定是最高的,我们知道,像素越高,在图像上越亮,当达到255的时候,是最亮,即为白色。所以我们可以通过这种方式来检测到直线。

2、API

1.HoughLines

接下来我们讲一下API。霍夫直线有两个API,首先我们先讲一个偏专业的

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
);

函数参数含义如下:

(1)InputArray类型的src ,8位,单通道二进制源图像。

(2)OutputArray类型的lines,直线的输出向量。每一直线都由一个双元素向量表示。rho是距坐标原点的距离(0,0)(图像左上角)。theta是以弧度为单位的线旋转角度。

(3)double类型的rho,累加器的距离分辨率(像素)

(4)double类型的theta,累加器的角度分辨率(弧度)。

(5)int类型的threshold,累加器阈值参数。只返回获得足够累加器数量的直线。

(6)double类型的srn,对于多尺度Hough变换,它是距离分辨率rho的除数,粗累加器距离分辨率为rho,精确累加器分辨率为rho/srn。如果srn=0和stn=0,则使用经典Hough变换。否则,这两个参数都应为正。

(7)double类型的sth,对于多尺度Hough变换,它是距离分辨率θ的除数。

(8)double类型的min_theta,用于标准和多尺度Hough变换,检查直线的最小角度。必须介于0和maxθ之间。

(9)double类型的max_theta,用于标准和多尺度Hough变换,用于检查线条的最大角度。必须介于最小θ和CVπ之间。

2.HoughLinesP

接下来我们先讲一个实用性更高的

HoughLines( 
InputArray image,
OutputArray lines,
double rho,
double theta,
int threshold,
double minLineLength = 0,
double maxLineGap = 0
);

函数参数含义如下:

(1)InputArray类型的src ,8位,单通道二进制源图像。

(2)OutputArray类型的lines,直线的输出向量。每一直线都由一个双元素向量表示。rho是距坐标原点的距离(0,0)(图像左上角)。theta是以弧度为单位的线旋转角度。

(3)double类型的rho,累加器的距离分辨率(像素)

(4)double类型的theta,累加器的角度分辨率(弧度)。

(5)int类型的threshold,累加器阈值参数。只返回获得足够累加器数量的直线。

(6)double类型的minLineLength,最小直线长度。小于该值的线段将被拒绝。

(7)double类型的maxLineGap,同一行上的点之间链接它们所允许的最大间距。

 

3、代码展示

如果我们使用HoughLines,代码如下:

#include<iostream>
#include<opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
Mat src, src_gray, dst;
src = imread("E:/image/HoughLines.bmp");
if (!src.data)
{
cout << "could not load image !";
return -1;
}
imshow("【输入图像】", src);

Canny(src, src_gray, 0, 255);
cvtColor(src_gray, dst, CV_GRAY2BGR);
imshow("【获取边缘】", src_gray);

vector<Vec2f> lines;
HoughLines(src_gray, lines, 1, CV_PI / 180, 100);

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(dst, pt1, pt2, Scalar(0, 0, 255), 5, CV_AA);
}


imshow("【输出图像】", dst);

waitKey(0);
return 0;
}

如果我们使用HoughLinesP,代码如下:

#include<iostream>
#include<opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
Mat src, src_gray, dst;
src = imread("E:/image/HoughLines.bmp");
if (!src.data)
{
cout << "could not load image !";
return -1;
}
imshow("【输入图像】", src);

Canny(src, src_gray, 0, 255);
cvtColor(src_gray, dst, CV_GRAY2BGR);

imshow("【获取边缘】", src_gray);

vector<Vec4f> plines;
HoughLinesP(src_gray, plines, 1, CV_PI / 180.0, 10, 0, 10);
cout << plines.size() << endl;
Scalar color = Scalar(0, 0, 255);
for (size_t i = 0; i < plines.size(); i++) {
Vec4f hline = plines[i];
line(dst, Point(hline[0], hline[1]), Point(hline[2], hline[3]), color, 3, LINE_AA);
}

imshow("【输出图像】", dst);

waitKey(0);
return 0;
}

4、执行结果

【opencv学习笔记】021之霍夫直线变换原理详解_霍夫变换_10

【opencv学习笔记】021之霍夫直线变换原理详解_霍夫直线变换_11

 


【opencv学习笔记】021之霍夫直线变换原理详解_霍夫变换_12

HoughLines

 


【opencv学习笔记】021之霍夫直线变换原理详解_霍夫变换_13

HoughLinesP

可以看到他把所有的直线全部都标注出来,大家也可以自己调整参数观看效果哦。

大家也可以自己尝试一下呀,一定要多做练习!

 

举报

相关推荐

0 条评论