本文大纲
自动驾驶中的车道线检测思路
车道线检测是 ADAS 领域和高级别自动驾驶都非常重要的一环,属于环境感知和定位中的核心项。
人可以轻易分辨道路上的车道线,但是对于机器而言,却非常的难,人脑有先验知识,有极速的上下文理解能力,但机器而言只有一张 2 维的图片,然后从中寻找有意义的特征,再拟合成曲线表达式的形式。
车道线检测的研究由来已久,大概分 2 种算法流派:
- 传统 CV 算法,主要是边缘检测,然后通过霍夫变换检测直线,再聚类,再拟合,这种算法很初级,鲁棒性很差,但因为简单是绝大多数同学入门车道线检测的 helloworld 算法。
- AI 算法,主要是 CNN,也有人用 CNN + LSTM,AI 天生就适合提取语义特征,也容易达到端到端的效果。
Apollo 6.0 源码中车道线是采用 dark scnn,应该是 scnn 一种翻版,scnn 就是一种用于检测车道线的 cnn。
SCNN 算法思想
SCNN 全称是 Spatial CNN,2018 年的产物。
论文地址:https://arxiv.org/pdf/1712.06080.pdf
本质上就是一个 Encoder-Decoder 模型。
上面的图片是 Encoder-Decoder 在 CV 中的应用示例,一般用来做图像语义分割。
SCNN 本质上也是一种图像语义分割,只不过它是 2 值语义分割。
它最有价值的一点在于提出了一种逐行逐列信息传递的过程,因为这个过程能够更加有效抓取到细长的物体特征,毫无疑问,车道线正是这种细长的物体。
上图中 SCNN_D、SCNN_U、SCNN_R、SCNN_L 分别代表下、上、右、左 4 个方向去执行数据的前向传播。
SCNN 最多处理 4 条车道线,这让它模型更专注。
实际道路中肯定不止 4 条车道线,但车道线数量的变化对于模型挑战很大,把数量固定在 4 条能很大程度上减轻模型的复杂度和负担。
并且 4 条车道线大多时候对于摄像头而言已经够了,因为它代表了 3 车道:左车道、自车道、右边车道。
之前我自己用霍夫变换+聚类处理车道线检测的时候有个很头痛的问题就是聚类的个数是个头痛的事情,因为驾驶环境中车道线的数量是变化的,有时是 2 条,有时变成 3 条,有时是 4 条,然后又变成 3 条之类,如果采用 k-means 算法的话,这个 k 就很难确定,当然用 DBSCAN 聚类的话可以解决这个问题,但算法的高效性存疑。
我当时的想法是做“AI+传统算法融合”:
- 一个极度轻量的 AI 模型去预测画面有几条车道线。
- 用传统 CV 算法去检测、拟合。
后来我看到 SCNN 的思路时会心一笑,其实差不多,它直接一步到位用多分支 AI 模型就解决了问题,实在是妙。
上图是 SCNN 车道线处理流程,左边分支应用 Encoder-Decoder 输出 heatmap,其实就是一张掩码图,代表了每个像素点是车道线的概率,右边分支做全局信息的预测,预测 4 条车道线存在的概率。
最终,根据右边分支的存在性概率向量,在左边的概率图上每隔 20 个像素寻找最高响应做采样,然后用 3次样条曲线完成拟合,车道线检测就这么愉快的结束了。
Apollo 中对应的 dark scnn 代码逻辑
前面一小节是 SCNN 论文算法思想,但 Apollo 中 scnn 是 dark scnn,我不知道 dark 的含义,但猜想肯定有些变化。
前面的文章讨论过车道线检测入口是 lane_detect_component,在其中的 onImageReceive 函数中处理,会调用 LaneCameraPerception 的 Perception 方法。
dark scnn 模型结构
定义文件位于:
modules/perception/production/data/perception/camera/models/lane_detector/darkSCNN/deploy.prototxt
借助于可视化工具 netron,可以看到它的结构。
可以看到层次非常多,所以,还需要结合源文件中的注释。
name: "darknet-16c-16x-3d multitask TEST 960x384, offset L3:440, L4: 312, RM DET"
# SCNN part: kernel size 5, only Up-Down direction
###################### LANE #######################3