自动驾驶:车道线检测算法

2018-08-30 11:14:19·  来源:九三智能控  
 
识别道路上的车道是所有司机的共同任务,以确保车辆在驾驶时处于车道限制之内,并减少因越过车道而与其他车辆发生碰撞的机会。
识别道路上的车道是所有司机的共同任务,以确保车辆在驾驶时处于车道限制之内,并减少因越过车道而与其他车辆发生碰撞的机会。

对自动驾驶汽车来说,这同样也是一项关键任务。事实证明,使用计算机视觉技术识别道路上的车道标记是可能的。本算法将介绍其中的一些技术。

这个项目的目标是创建一种方法,使用Python和OpenCV在道路上找到车道线。

实例图像

Udacity提供了960 x 540像素的示例图像,用于训练我们的算法。下面是提供的两个图像。



算法步骤

在这一部分中,我们将详细介绍本算法所需的不同步骤,这将使我们能够识别和分类车道线,如下所示:

将原始图像转换为HSL
从HSL图像中分离出黄色和白色
将分离的HSL与原始图像相结合
将图像转换为灰度,便于操作
应用高斯模糊来平滑边缘
在平滑的灰色图像上应用Canny边缘检测
跟踪感兴趣的区域,并剔除其他区域的信息
执行一个霍夫变换,在我们感兴趣的区域内找到车道,并用红色跟踪它们
分开左车道和右车道
插入直线梯度来创建两条平滑的直线

每个步骤的输入都是前一步的输出(例如,我们对区域分割图像应用Hough变换)。

转换到不同的色彩空间

虽然我们的图像目前是RBG格式,但是我们应该探索在不同的颜色空间,如HSL或HSV中进行可视化,看看它们是否能够帮助我们更好地隔离车道。注意,HSV通常被称为HSB(色相饱和度和亮度)。

下面的图表使我们能够看到两者之间的区别:



HSV



HSL

下图显示了原始图像及其HSV和HSL格式。




可以看出,HSL比HSV更擅长对比车道线。HSV对白线“模糊”了太多,所以在这种情况下不适合我们选择。至少,使用HSL隔离黄色和白色的车道会更容易些。

分离出黄色和白色

我们首先从原始图像中分离出黄色和白色。在这样做之后,我们可以观察到黄色和白色的车道是如何很好地隔离。



现在我们使用OR操作合并这两个掩码,然后使用AND操作与原始映像合并,并仅保留相交的元素。



到目前为止,结果非常令人满意。看看我们的HSL黄面罩是如何清晰地识别黄色路标的!接下来,我们将对图像进行灰度化处理。

转换为灰度图

我们感兴趣的是如何检测图像上的白线或黄线,当图像是灰度的时候,这些线的对比度特别高。记住,道路是黑色的,所以任何在道路上更亮的东西都会在灰度图像中产生高对比度。

从HSL到灰度的转换有助于进一步降低噪声。在我们能够运行更强大的算法来隔离行之前,这也是一个必要的预处理步骤。



高斯模糊

高斯模糊(也称为高斯平滑)是一种预处理技术,用于平滑图像的边缘以减少噪声。我们反直觉地采取这个步骤来减少我们检测到的行数,因为我们只想关注最重要的线条(车道线),而不是每个对象上的条。我们必须小心,不要把图像弄得太模糊,否则很难画出一条线条来。

高斯模糊的OpenCV实现采用整数核参数来表示平滑的强度。对于我们的任务,我们选择一个值为11。

下面的图像显示了典型的高斯模糊对图像的影响,原始图像在左边,而模糊图像在右边。



Canny边缘检测

现在已经对图像进行了充分的预处理,我们可以应用Canny边缘检测器,它的作用是识别图像中的边缘并剔除所有其他数据。最终得到的图像是线条型的,这使我们更关注于车道检测,因为我们关注的是线条。

OpenCV实现除了模糊图像外,还需要传递两个参数,一个低阈值和一个高阈值,它决定是否包含给定的边缘。阈值捕获给定点的变化强度(可以将其视为梯度)。

超过高阈值的任何点都将包含在我们的结果图像中,而阈值之间的点只有在接近高阈值的边缘时才会包含。低于阈值的边被丢弃。推荐低:高阈值比率为1:3或1:2。对于低阈值和高阈值,我们分别使用值50和150。

下面我们一起展示平滑的灰度和精明的图像:



关注区域

下一步是确定感兴趣的区域,并丢弃这个区域之外的任何线。在这项任务中,一个关键的假设是,摄像机在所有这些图像上都保持在相同的位置,而且车道是平的,因此我们可以识别我们关注的关键区域。

看看上面的图片,我们根据汽车所在车道的轮廓“猜测”这个区域可能是什么,并定义一个多边形,它将作为我们的关注区域。

我们将精明的分割图像并排放在一起,观察如何只保留最相关的细节:



霍夫变换

下一步是应用霍夫变换技术提取线条并给它们上色。霍夫变换的目标是通过识别所有的点来找到线。这是通过将我们当前用轴(x,y)表示的系统转换成轴为(m, b)的参数系统来实现的。

直线被表示为点
点被表示为线
相交的线意味着同一点在多条线上

因此,在这样的平面中,我们可以更容易地识别出经过同一点的直线。然而,我们需要从当前的系统移动到使用极坐标系统的霍夫空间,因为当m=0(即垂直线)时,我们的原始表达式是不可微的。

所有直线将通过一个给定的点对应于一个正弦曲线(ρ和θ)。因此,一组点相同的直线在笛卡尔空间将产生正弦曲线交叉的点(ρ和θ)。这自然意味着在笛卡尔空间的直线上探测点的问题被简化为在霍夫空间中寻找交叉的正弦信号。



霍夫变换返回的车道线如下所示:



区分车道

为了能够跟踪整条线并连接图像上的车道标记,我们必须能够区分左车道和右车道。幸运的是,有一种简单的方法可以做到这一点。如果仔细观察图像(使用精明的分割图像可能更容易),您可以得到任何左车道线或右车道线的梯度。

左车道:当x值(即宽度)增大时,y值(即高度)减小:因此斜率必须为负
右车道:当x值(即宽度)增加时,y值(即高度)增加:因此斜率必须为正

因此,我们可以定义一个函数,将行分隔为左和右。当梯度的分母(dy/dx)为0时,我们必须小心,忽略任何有这条直线的直线。

在下面的图片中,我们用红色标注属于左车道的线条,而属于右车道的线条用蓝色标注:



梯度插值和线性外推

要从屏幕底部跟踪到感兴趣区域的最高点,我们必须能够插入霍夫变换函数返回的不同点,并找到一条使这些点之间的距离最小化的线。基本上这是一个线性回归问题。我们将尝试通过最小化最小二乘误差来找到给定车道上的直线。我们方便地使用scipy.stats. linregress(x,y)函数的作用是:求车道线的斜率和截距。

我们成功地做到了这一点,如下图所示:



视频上的应用

我们还提供了三段视频来验证本算法:
(1)10秒的视频,只有白色的车道线
(2)一段27秒的视频,左边是一条连续的黄线,右边是白色的线
(3)这是一个挑战视频,道路稍微弯曲,帧的分辨率更高

首要任务

算法在前两个视频中运行得还不错,但在挑战练习中完全失败了。

为了使车道检测更平滑,并利用每一帧的排序和位置(因此也包括车道),我决定在帧之间插入泳道梯度和截取,并剔除任何与前一帧的计算平均值偏离太多的线。

车道检测器

记住,视频是一系列的帧。因此,如果在t坐标系下,我们计算出的直线与我们在坐标系[0,t-1]中计算出的直线斜率和截距的平均值有不相称的差异,那么我们就可以利用之前坐标系中的信息来平滑我们在路上跟踪的直线,并采取纠正步骤。

因此,我们需要将内存的概念引入管道中。我们将使用一个标准的Python deque来存储最后的N个(我现在将它设置为15)计算的行系数。

这工作相当首先在两个视频,甚至设法体面地挑战视频检测车道线,但由于有曲率的车道直线由一个简单的多项式学位1(即y = Ax¹+ b)是不够的。将来我将在弯曲的道路上设计更好的车道线。

存在的问题

我观察到目前车道线检测的一些问题:
在第二节的挑战视频中,车道上覆盖了一些阴影,我的代码最初没有检测到它。我通过将HSL颜色过滤作为另一个预处理步骤来解决这个问题。

当道路上有弯道时,直线就不起作用了。

霍夫变换的参数很难处理正确。

后续改进

算法的另一个探索是计算内存探测器中线系数的加权平均值,使最近的系数具有更高的权重,因为它们属于最近的帧。我相信帧的局部性将在视频中获得接近完美的车道线起着至关重要的作用。

我们还应该考虑将车道线表示为二级多项式来处理。

在未来,我们还计划利用深度学习来识别车道,并将这些结果与我用纯粹的计算机视觉方法得到的结果进行比较。

这是一个令人兴奋和富有挑战性的算法,它让我们对色彩空间、图像处理和一些线性代数的应用有了更多的了解。

分享到:
 
反对 0 举报 0 收藏 0 评论 0
沪ICP备11026917号-25