目录
一、前言
二、霍夫变换
1、霍夫变换是个啥
2、常用霍夫变换
三、霍夫直线变换
1、讲解
2、API
1.HoughLines
2.HoughLinesP
3、代码展示
4、执行结果
终于更新到霍夫直线变换了,跟以前写的博客成功接轨。opencv基础博客也即将更新完毕,感谢大家的支持,我们要再接再厉呀!
如果想看其他有关于OpenCV学习方法介绍、学习教程、代码实战、常见报错及解决方案等相关内容,可以直接看我的OpenCV分类:
【OpenCV系列】:https://blog.csdn.net/shuiyixin/article/category/7581855
如果你想了解更多有关于计算机视觉、OpenCV、机器学习、深度学习等相关技术的内容,想与更多大佬一起沟通,那就扫描下方二维码加入我们吧!
我们先来了解一下霍夫变换是个啥
霍夫变换是一种特征检测(feature extraction),被广泛应用在图像分析(image analysis)、计算机视觉(computer vision)以及数位影像处理(digital image processing)。
霍夫变换是用来辨别找出物件中的特征,其流程大致如下:
给定一个物件、要辨别的形状的种类,算法会在参数空间(parameter space)中执行投票来决定物体的形状,而这是由累加空间(accumulator space)里的局部最大值(local maximum)来决定。
我们会经常使用到如下两个霍夫变换:
1.霍夫直线变换:在图像中寻找直线
2.霍夫圆变换:在图像中寻找圆。
这个博客,我们一起来了解一下啥是霍夫直线变换,。如果你想了解霍夫圆变换,请转移到:
【opencv学习笔记】022之霍夫圆变换:https://blog.csdn.net/shuiyixin/article/details/79898107
上面我们知道霍夫直线变换,就是用来检测直线的,那怎么知道一条线是直线呢?
假设我们有上图这个红色的直线,大家看到这个θ和r,学过极坐标的同学应该就能知道了,我们要用极坐标来表示直线了。
对于一条直线来说,我们首先要知道它的平面直角坐标表示(只考虑二维平面):
而对于上图,我们能知道:
根据上面的公式,我们能够推导出如下公式:
推导过程可以如下:
得到这个公式,有什么作用呢?
我们知道x和y是直线上的点,我们为了方便讲解,我们取一条直线来说明:
对于上面这条直线,有如下五个点是在直线上的:
所以我们可以得到五条直线:
如果我们以θ为横坐标,r为纵坐标,当我们把这五条直线画在同一个坐标系中,我们能得到下面这幅图:
我们发现,这五条直线交于同一点,这就是直线有的特点,我们就通过这个特点,将所有的直线累加,那交点处因为是所有直线的累加,其像素值一定是最高的,我们知道,像素越高,在图像上越亮,当达到255的时候,是最亮,即为白色。所以我们可以通过这种方式来检测到直线。
接下来我们讲一下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π之间。
接下来我们先讲一个实用性更高的
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,同一行上的点之间链接它们所允许的最大间距。
如果我们使用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;
}
可以看到他把所有的直线全部都标注出来,大家也可以自己调整参数观看效果哦。
大家也可以自己尝试一下呀,一定要多做练习!