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

目录

一、前言

二、霍夫变换

1、霍夫变换是个啥

2、常用霍夫变换

三、霍夫直线变换

1、讲解

2、API

1.HoughLines

2.HoughLinesP

3、代码展示

4、执行结果


一、前言

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

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

【OpenCV系列】:https://blog.csdn.net/shuiyixin/article/category/7581855

如果你想了解更多有关于计算机视觉、OpenCV、机器学习、深度学习等相关技术的内容,想与更多大佬一起沟通,那就扫描下方二维码加入我们吧!

 

二、霍夫变换

1、霍夫变换是个啥

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

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

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

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

 

2、常用霍夫变换

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

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

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

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

【opencv学习笔记】022之霍夫圆变换:https://blog.csdn.net/shuiyixin/article/details/79898107

 

三、霍夫直线变换

1、讲解

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

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

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

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

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

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

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

推导过程可以如下:

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

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

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

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

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

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

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

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

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

我们发现,这五条直线交于同一点,这就是直线有的特点,我们就通过这个特点,将所有的直线累加,那交点处因为是所有直线的累加,其像素值一定是最高的,我们知道,像素越高,在图像上越亮,当达到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
#include

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 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
#include

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 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之霍夫直线变换原理详解_第7张图片

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

 

【opencv学习笔记】021之霍夫直线变换原理详解_第9张图片 HoughLines

 

【opencv学习笔记】021之霍夫直线变换原理详解_第10张图片 HoughLinesP

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

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

 

你可能感兴趣的:(opencv,霍夫直线变换,霍夫变换)