基于深度学习的车道检测

简介: 基于深度学习的车道检测

人们可以很容易地在道路上找到车道线,即使在各种各样的条件下也是如此。除非大雪覆盖地面、暴雨、道路非常脏或年久失修。虽然你们中的一些人可能已经想挑战其他司机是否真的成功地保持在线内,但即使没有任何驾驶经验,你也知道那些黄线和白线是什么。

另一方面,计算机却发现这并不容易。阴影、眩光、道路颜色的微小变化、线路的轻微障碍……人类通常仍然可以处理的所有事情,但计算机可能很难处理。以至于在 Udacity 的自动驾驶汽车纳米学位的第 1 学期,他们将五个项目中的两个集中在这个问题上。第一个是一个很好的介绍,用于向学生介绍一些基本的计算机视觉技术,例如 Canny 边缘检测。


Canny 边缘检测

第二学期的第四个项目中,我们进行了更深入的研究。这一次,我们使用了一个叫做透视变换的概念,它拉伸了图像中的某些点(在这种情况下,车道线的“角点”,从车道在汽车下方的图像底部延伸到线在远处汇聚的地平线)到目的地点,在道路的情况下,它看起来就像一只鸟在头顶飞过。


图像的透视变换

在透视变换之前,梯度(当你穿过图像时像素值的变化,就像黑暗的道路变成亮线的地方)和颜色阈值可以用来返回一个二值图像,它只在值大于你的值时被设定为给定的阈值。透视变换后,可以在该线上运行一个滑动窗口来计算车道线曲线的多项式拟合线。


具有二元激活的“S”通道或饱和度


更大阈值(左),以及由此产生的透视变换


滑动窗口和效果图结果


这似乎可以正常工作,但有一些很大的限制。首先,透视变换对于相机(在变换之前也需要单独不失真)、相机的安装,甚至汽车所处道路的倾斜度来说都是相当特定的。其次,各种渐变和颜色阈值仅在一小部分条件下有效——我一开始提到的计算机在识别车道线时遇到的所有问题在这里变得非常明显。最后,这种技术很慢——我用来将预测车道检测生成回视频的技术只能以大约每秒 4.5 帧 (fps) 的速度运行,而来自汽车的视频可能会以大约 30 fps 或更高的速度运行。


当车道检测出错时


SDCND 第 1 学期的另外两个项目专注于深度学习,在这些案例中用于交通标志分类和行为克隆(让虚拟汽车根据输入的图像以特定角度转向,在训练时复制您的行为)。五个项目中的最后一个项目也有可能采用深度学习,尽管主要方法使用了不同的机器学习技术。


数据


我的第一个决定,也许是最重要的(不幸的是,也许也是最耗时的)是决定创建我自己的数据集。尽管有很多数据集用于训练潜在的自动驾驶汽车(几乎每天都在增加),但它们大多没有标记汽车自己的车道。此外,我认为创建一个充分精选的数据集来训练深度神经网络将是一个有趣且有益的挑战。


收集数据很容易。我住在加利福尼亚州圣何塞,我可以开车去很多地方。从我之前的深度学习项目中,我知道大型数据集的重要性,但也许更重要的是,拥有一个平衡的数据集是多么重要。我在高速公路、小路上开车,沿着非常弯曲的道路上山腰,在晚上、在雨中(幸运的是,当我去收集这些数据时,加州的干旱完全逆转了)。虽然听起来可能不是很多,但我最终得到了将近 12 分钟的驾驶时间,这转化为超过 21,000 个单独的图像帧,全部来自我的智能手机。

在找到提取图像帧的好方法后,我几乎立即注意到了一个问题。虽然我在较亮的条件下开得较慢的视频主要由高质量图像组成,但夜间高速公路驾驶和雨中驾驶有大量模糊图像(我将夜间高速公路驾驶问题归咎于圣何塞高速公路的颠簸就像我手机在黑暗中的问题一样)。我必须单独检查每张图像,否则我的神经网络可能永远无法学习任何东西。我突然减少到 14,000 张图像,仍然有意留下一些稍微模糊的图像,以希望在未来进行更强大的检测。


获取和删除不良数据的示例。经过训练的模型在后来预测此图像的车道时实际上做得很好!


为了实际标记我的数据集,我计划仍然使用我以前的基于计算机视觉的技术。这意味着通过我的旧算法处理图像,而不是输出顶部绘制预测车道的原始图像,而是输出六个多项式系数,或者为每条车道线输出三个值(即方程 ax² +bx+c中的 a、b 和 c)。当然,如果我只是单纯地使用我的旧算法进行标记,我只会训练我的神经网络来解决与旧模型相同的问题,并且我希望它更健壮。我决定以一种颜色(我选择了红色)手动重新绘制真实的车道线,这样我就可以使用红色通道阈值来更好地检测车道线。我原本以为我要处理 14,000 张图像,但很快意识到这会花费太长时间(除非我像 comma.ai 一样幸运/人脉广泛并且可以众包我的标签)。相反,考虑到时间对数据的影响(如果我以低速在彼此几帧内输入图像,模型可能会“窥视”它自己的验证集,因为变化不大),我决定只对十分之一的图像执行此过程,从而创建一组早期的 1,400 张训练图像。





绘制一些模糊的线条。考虑到最终模型即使在模糊的夜间图像中仍能检测到车道的能力,看来这种方法确实有助于增强鲁棒性。


此时,我创建了一个程序,可以在道路图像上使用我的旧的基于 CV 的模型,检测车道多项式,并重新绘制,类似于我在之前的项目中所做的。这保存了每张生成的图像,因此我可以检查哪些标签不够。我注意到了一个紧迫的问题——尽管我已经为旧模型提供了相当多的弯曲道路,但它几乎无法正确检测到所有这些道路上的线路。我输入的 1,400 张图片中有将近 450 张无法使用,其中大部分是曲线。

然而,我意识到这是由于原始方法本身的性质——滑动窗口的工作方式。如果车道线离开图像的一侧,原始滑动窗口将继续垂直向上图像,导致算法认为该线也应该朝那个方向绘制。这是通过检查窗口框是否接触到图像的一侧来解决的——如果是的话,并且窗口已经在图像上向上移动了一点(以防止模型在窗口靠近时在开始时完全失败),然后滑动窗口将停止。


曲道路上的原始滑动窗口,与在边缘切割窗口搜索(也有更多窗口)


这种方法非常有效!我将失败率减半,从原来的 ~450 张失败图像减少到 ~225 张。他们仍然有很多极端曲线在这里失败,所以我想检查标签的实际分布情况。我通过使用直方图实际检查六个系数中的每一个的分布来做到这一点。我又一次失望了。数据仍然过于偏向直线。我甚至只添加了我拍摄的弯曲道路视频中的其他图像。当我查看图像时,问题仍然很明显——即使在非常弯曲的道路上,大部分车道仍然相当笔直。

车道线系数之一的原始分布——过于集中于直线


我的独立交通标志分类项目中的一个重大差异制造者一直在通过为任何交通标志类别添加原始图像集的小旋转来创建“假”数据,而数据中的表示很少。再次使用这种方法,对于某个分布范围之外的任何系数标签(我迭代了大约外部 400、100 和 30 张图像,这意味着最远的外部实际上经历了 3倍的过程),图像被轻微旋转,同时保持同一个标签。


为曲线数据添加图像旋转后,单线系数的数据分布更均匀


在这个过程之后,每个系数的数据终于分布得更均匀了。我还使用了一些其他快速预处理项目来处理图像和标签。训练图像从原来的 720 x 1280 重新调整大小(我最终尝试了缩小 4 倍、8 倍和 16 倍的不同版本)并归一化(这有助于模型的最终收敛)。我还使用 sklearn 中的 StandardScaler 对标签进行了标准化(如果您这样做,请确保保存缩放器,以便您可以在模型结束时将其反转!)。这种标签规范化可能会有点欺骗你,因为训练中的损失会自动降低,但我发现绘制回图像时的最终结果也更加令人印象深刻。


下一节我们将继续创建和训练模型。


在创建了一个不错的数据集后,我准备制作我的第一个使用深度学习检测车道线的模型。


透视转换模型


你可能会问,“等等,我以为你在试图摆脱透视变换?”这是真的。然而,为了创建一个初始模型架构,我想检查它是否在给定有限的数据集时,看起来像深度学习一样可以学习做与基于 CV 的模型相同的事情。因此,这里的输入是透视变换的道路图像,因此神经网络更容易学习系数似乎是合乎逻辑的。

我在这里使用了与我之前在行为克隆项目中使用的模型架构类似的模型架构,包括批量归一化层、卷积层、池化层、展平层和全连接层。最终的全连接层的输出大小为 6,用于预测车道线系数的数量。我还使用了 Keras 的 ImageDataGenerator 来尝试使模型更健壮(主要是旋转、高度偏移和垂直翻转——水平翻转操作让我比较担心,因为标签需要更改才能准确描绘线条信息)。经过一些微调(模型架构、参数和输入图像大小)后,模型产生了一个不错的结果,但它非常严格地依赖于输入和输出的透视变换。


道路图像模型


在发现深度学习可以处理我的数据集后,我开始创建一个模型,该模型可以在没有任何透视变换的情况下接收道路图像。我使用与以前完全相同的架构,除了添加“裁剪”层以裁剪图像的前三分之一。我的预期是任何给定道路图像的前三分之一很少(如果有的话)包含检测车道所需的信息。该模型很容易收敛到与透视变换模型相似的结果,因此我知道我可以放弃对输入模型的原始图像进行透视变换的需要。


在这一点上,我想使用与我自己手机不同的摄像头为我的模型提供一些额外的数据(以解决不同的摄像头失真问题),因此我为它提供了一些来自我之前项目的 Udacity 常规项目视频的帧。然而,这里的问题在于为这些数据创建新标签——我用来标记我自己的数据的透视变换与这个单独视频的不同。这也让我意识到我最初处理问题的方式存在一个巨大的问题——标签本身在鸟瞰的角度是多项式系数,这意味着在预测和绘制车道后,车道仍然需要反向转换回原始图像的视角。

这导致了一个似乎相当无法泛化的模型,但通过仅在我自己的一个视频上查看生成的结果,我意识到也许该模型仍在正确检测线条,只是无法重现良好的视觉结果,因为到预测后仍在使用的透视变换。该模型似乎在视角不同的地方遇到了麻烦(在单独的 Udacity 视频和我自己视频的更多丘陵点的情况下)。但是,如果它真的学会了检测线条会怎样——如果我可以直接观察层本身的激活情况会怎样?然后我可能会在原始视频的顶部显示图层的激活。


使用 keras-vis 激活库


我很快发现了 keras-vis 这个优秀的存储库,这正是我所需要的。在此之前,我找到了几篇关于同一概念的研究论文,但找不到重现结果所需的实际代码。keras-vis 库很棒,因为它允许您将经过训练的模型输入一个函数,并返回所需层的激活图,技术上是为典型分类神经网络中的每个“类”制作的,但在这种情况下是为每个我的多项式系数。


前几层的激活图(注意层的前三分之一已经被裁剪掉了)


这是一种非常有趣的方式,可以准确地查看我的卷积神经网络在我的道路图像中看到的内容。虽然上图在第一层看起来不错,但这种方法当然存在更多问题。


首先,在我的许多弯曲道路图像中,模型实际上只看其中一条线。我的模型了解到线条之间存在一种关系,这是因为——在大多数情况下,车道线将是平行的,所以如果你只看一条线(假设两条线总是相同的) ,您可以大致了解另一条线所在的位置。但这对我没有帮助,因为我希望能够显示两条线或车道本身的位置。另外,如果你在上面注意到,可能是由于模型生成器中我的图像翻转,激活也大量发生在天空中——模型正在学习根据图像中天空的位置来定位自己,所以如果我想在我的原始视频上显示它,就必须以某种方式删除这个激活区域。


更深层次的可视化


第二个问题更令人困惑。弯曲的道路倾向于在单条直线和天空上激活,而直线道路则在图像底部的汽车本身以及汽车本身正前方的空间上激活。在图像的上方,线条有时会被激活。如果弯道和直道之间的激活没有任何一致性,这种方法是行不通的。


迁移学习


我为使用 keras-vis 保存方法所做的最后一次尝试是使用迁移学习。我完全忘记了我的行为克隆项目,在该项目中,一辆模拟汽车根据呈现给其经过训练的神经网络的图像学会了自行驾驶。等一下——我使用 20,000 多张图片训练了一个模型,让它在路上行驶——这样做是为了什么?


模拟汽车的输入图像之一


答案实际上是整条路本身(Udacity 的模拟器中没有单独的车道),但我想知道我是否可以使用迁移学习来更好地立即集中模型的注意力。使用更大的数据集开始训练,然后我可以使用特定于我的车道检测的新数据添加一些额外的训练,并希望有更好的激活层。从该项目加载经过训练的模型后使用 model.pop(),我从中删除了最终输出层(这是一个单一的输出,用于转向角),并将其替换为我的系数标签的六个输出。请注意,如果您自己使用模型来匹配输入图像大小,否则它不会起作用。


它工作得更好一些,因为模型在使用我自己的数据进行一些额外训练后,开始查看车道线而不是整条道路以进行激活。然而,在图像的哪些部分被激活、它们的激活程度等等方面仍然存在很大的一致性问题。


完全卷积的方法


感觉自己快要失败了,我开始寻找新的方法。我最近看到几个不同的小组处理来自汽车摄像头的图像的一个领域是图像分割——将给定的图像划分为道路、汽车、人行道、建筑物等类别。SegNet 是图像分割之一我发现这些技术很有趣,他们甚至发布了他们的通用模型架构,该架构使用卷积层(具有批量归一化和 ReLU 激活)结合下摆的池化层,以及从中点到中点的上采样(基本上是反池化)和反卷积层分割后的图像。这种方法会跳过任何完全连接的层,从而形成一个完全卷积神经网络。


这似乎是解决车道可能以错误的视角重新绘制的问题的潜在解决方案——为什么不让神经网络自己重新绘制预测的车道呢?我仍然可以输入道路图像,同时使用原始系数标签创建的车道图作为新标签(即输出图像)。考虑到我已经用绿色绘制了车道,我决定让我的模型的输出“过滤器”只是 RGB 的“G”通道(并且只需将两个空白过滤器与其叠加,以便将相应的图像与原始道路图像)。这也有助于我将数据集的大小增加一倍——还记得我之前是多么担心水平翻转图像的潜在不良影响吗,因为系数标签与神经网络所看到的不匹配?通过切换到这种方法,在预处理数据时,我可以同时翻转道路图像和车道图像标签。


新标签之一——车道图像


此时我将快速后退一步查看数据集:

  • 我的原始数据有 1,420 张图像,我删除了其中 227 个无法正确标记的内容
  • 我仅从弯曲的道路视频中添加了 568 张图像(我尝试使用其中的 1,636 张 - 由于我用于标记的 CV 模型不够充分,很多仍然失败)
  • Udacity 常规项目视频中的另外 217 张图片
  • 总共有 1,978 张图片
  • 原始系数上的各种小图像旋转没有很好地表示,我最终得到了 6,382 张图像
  • 水平翻转将其翻倍至 12,764 张图像


请注意,我仍然能够对这些新标签使用图像旋转,只要确保在我运行这些系数在主要分布之外时保持道路图像、系数标签和车道图像标签的链接。


考虑到我以前从未使用过全卷积神经网络,我想非常仔细地遵循 SegNet 的架构。幸运的是,使用 Keras 这样做并不太复杂——与反卷积层的一个区别是你必须确保将数学与你想做的事情正确匹配。我通过在最终池化层之后精确镜像我的模型,以及对 80 x 160 x 3 的输入图像使用略有不同的纵横比(而保持原始纵横比将有 90 x 160 x 3)来使这变得容易。这样做也是为了让数学更简单——因为我使用 2 x 2 作为我的池化层的尺寸,从 90 开始会很快到达不能精确除以 2 的层。


我的新结构的简化模型(从左至右)


我创建的模型中存在一些小问题,因为我发现我在尝试根据需要向我的每个卷积层和反卷积层添加批量归一化和 drop-out 时内存不足(在上面你会注意到我在开始和结束的最宽的层没有 drop-out,当它们真的是最有效的点时)。我决定在开始时只进行批量归一化,然后在隐藏层中 drop-out。最后的反卷积层输出一个尺寸为 80 x 160 的滤波器(我将其用作“G”颜色通道),以更轻松地匹配原始道路图像。我还在开始训练之前通过除以 255 对车道图像标签进行了归一化(这意味着输出需要在预测之后乘以 255),这改善了收敛时间和最终结果。


比较不同模型的结果


最终结果要好得多。当然,这个视频已经看到了一大块图像(可能在 10-20% 之间),所以就此打住是作弊,尽管它在旧的基于 CV 的模型具有的区域更有效最初未能生产足够的标签。真正的测试是来自优达学城 Advanced Lane Lines 项目的挑战视频——我的模型从未见过其中的一帧。但它在这个视频上的表现也很好!它在高速公路立交桥下的阴影方面存在一些问题,但在其他方面学会了泛化到一个全新的视频。此外,它比旧模型快得多——通常能够使用 GPU 每秒处理 25-29 帧,仅次于 30 fps 的实时帧率。即使没有 GPU 加速,它仍然比 CV 模型快一点,达到 5.5 fps,而之前只有 4.5 fps。


旧的 CV 模型与新的模型对比


潜在的改进


这就是我使用深度学习进行车道检测的方法。当然它并不完美。它比基于 CV 的模型更稳健,但在 Udacity 发布的更难挑战视频中,虽然做出了令人钦佩的尝试,但仍然在一些光线干扰时,检测结果差强人意。以下是我对未来改进模型的一些想法:

  • 更多数据。当然,在深度学习中总是如此,但我认为在更广泛的条件下和更多不同的相机,模型可以变得更好。
  • 使用递归神经网络。我还没有学习实际为其中之一创建网络架构背后的技术,但考虑到它能够使用过去的信息进行下一次预测,我认为这将是一个非常有用的方法。
  • 使用没有车道线或只有一条线的数据。这当然可以用在更多的情况下——许多社区或城市以外的地区并没有标记所有车道线
  • 扩展模型以检测更多项目——类似于图像分割,为什么不添加车辆和行人检测?最后,我可以在单独的滤波器上执行这些操作,经过我用于通道的“G”通道的单个滤波器(不一定仅限于“R”和“B”通道)。这可能比常规图像分割更好,也可能不会更好。
相关文章
|
6天前
|
机器学习/深度学习 算法 计算机视觉
基于yolov2深度学习网络的火焰烟雾检测系统matlab仿真
基于yolov2深度学习网络的火焰烟雾检测系统matlab仿真
|
6天前
|
机器学习/深度学习 算法 计算机视觉
基于深度学习的停车位关键点检测系统(代码+原理)
基于深度学习的停车位关键点检测系统(代码+原理)
164 0
|
6天前
|
机器学习/深度学习 编解码 API
深度学习+不良身体姿势检测+警报系统+代码+部署(姿态识别矫正系统)
深度学习+不良身体姿势检测+警报系统+代码+部署(姿态识别矫正系统)
72 0
|
6天前
|
机器学习/深度学习 算法
m基于深度学习的QPSK调制解调系统相位检测和补偿算法matlab仿真
m基于深度学习的QPSK调制解调系统相位检测和补偿算法matlab仿真
50 2
|
6天前
|
机器学习/深度学习 算法 计算机视觉
m基于yolov2深度学习的车辆检测系统matlab仿真,带GUI操作界面
MATLAB 2022a中实现了YOLOv2目标检测算法的仿真,该算法从Darknet-19提取特征,以实时预测图像内目标的位置和类别。网络结构结合了网格划分、Anchor Boxes和多尺度预测,优化了边界框匹配。核心代码包括数据集划分、预训练ResNet-50加载、YOLOv2网络构建及训练。训练选项设置为GPU加速,使用'sgdm'优化器,200个周期进行训练。
26 2
m基于yolov2深度学习的车辆检测系统matlab仿真,带GUI操作界面
|
6天前
|
机器学习/深度学习 算法 计算机视觉
基于yolov2深度学习网络的视频手部检测算法matlab仿真
基于yolov2深度学习网络的视频手部检测算法matlab仿真
|
6天前
|
机器学习/深度学习 传感器 算法
【OpenCV】告别人工目检:深度学习技术引领工业品缺陷检测新时代
【OpenCV】告别人工目检:深度学习技术引领工业品缺陷检测新时代
|
6天前
|
机器学习/深度学习 存储 算法
m基于Yolov2深度学习网络的螺丝检测系统matlab仿真,带GUI界面
MATLAB 2022a中展示了YOLOv2算法的螺丝检测仿真结果,该系统基于深度学习的YOLOv2网络,有效检测和定位图像中的螺丝。YOLOv2通过批标准化、高分辨率分类器等优化实现速度和精度提升。核心代码部分涉及设置训练和测试数据,调整图像大小,加载预训练模型,构建YOLOv2网络并进行训练,最终保存检测器模型。
25 3
|
6天前
|
机器学习/深度学习 算法 计算机视觉
m基于Yolov2深度学习网络的人体喝水行为视频检测系统matlab仿真,带GUI界面
MATLAB 2022a中使用YOLOv2算法对avi视频进行人体喝水行为检测,结果显示成功检测到目标。该算法基于全卷积网络,通过特征提取、锚框和损失函数优化实现。程序首先打乱并分割数据集,利用预训练的ResNet-50和YOLOv2网络结构进行训练,最后保存模型。
31 5
|
6天前
|
机器学习/深度学习 算法 计算机视觉
基于深度学习的停车场车辆检测算法matlab仿真
该文介绍了使用GoogLeNet进行停车场车辆检测的算法,基于深度学习的CNN模型,利用Inception模块提升检测效率。在matlab2022a中实现,通过滑动窗口和二分类交叉熵损失函数优化。文章展示了几张算法运行效果和测试结果的图片,并提供了一段核心代码示例,涉及图片读取、划分、特征提取和分类。为了适应任务,进行了数据集准备、滑窗参数设定,并以平均精度为评估标准。