无人驾驶环境感知 车道线检测网络 LanNet 原理及实现

一、LaneNet 算法详解

1.1 LaneNet 简介

传统的车道线检测方法依赖于手工提取的特征来识别,如颜色的特征、结构张量、轮廓等,这些特征还可能与霍夫变换、各种算子或卡尔曼滤波器相结合。在识别车道线之后,采用后处理技术来过滤错误检测并将其分组在一起以形成最终车道。然而,由于道路场景的变化,这些传统的方法容易出现鲁棒性问题!

 

学习资源地址 https://gitee.com/studywangke/zdjs

更新的方法利用深度学习模型,这些模型被训练用于像素级车道分割。但这些方法仅限于检测预定义的固定数量的车道,例如当前车道,并且不能应对车道改变。

基于此,2018 年 Davy Neven 等人提出一种新的车道线检测网络 LaneNet,LaneNet 主要做出了如下两个贡献

  • 将车道检测问题归结为一个实例分割问题,其中每条车道都形成了自己的实例,可以端到端地进行训练。
  • 构建了一个新的网络 H-Net,用于学习给定输入图像的透视变换参数,该透视变换能够对坡度道路上的车道线进行良好地拟合,克服了鲁棒性不好的问题。

1.2 整体结构分析

作者提出了一个多分支的网络结构,包含一个二值化分割网络 (lane segmentation) 和一个实例分割网络 (lane embedding),从而实现端到端、任意数量的车道线检测。具体来说,二值分割网络输出所有的车道线像素,而实例分割网络将输出的车道线像素分配到不同的车道线实例中。整体的网络结构图如下:
 

在这里插入图片描述


另一方面,数据集输入到 H-Net 网络中,学习到透视变换参数 H 矩阵。用于不同车道线实例的像素,进行车道线拟合,从而得到上图所示连续点状的车道线。

1.3 LaneNet 网络结构

LaneNet 的整体网络结构如下:
 

在这里插入图片描述


二值化分割网络

Lanenet 的一个分支为二值化分割网络,该网络将车道线像素与背景区分开。由于目标类别是 2 类(车道 / 背景),并且高度不平衡,因此参考了 ENet,损失函数使用的是标准的交叉熵损失函数

实例分割网络

该分支网络参考了《Semantic Instance Segmentation with a Discriminative Loss Function》,使用基于 one-shot 的方法做距离度量学习,将该方法集成在标准的前馈神经网络中,可用于实时处理。该分支网络训练后输出一个车道线像素点距离,基于归属同一车道的像素点距离近,不同车道线像素点距离远的基本思想,利用聚类损失函数聚类得到各条车道线。

聚类损失函数

损失函数如下:
 

在这里插入图片描述


     [ x ] + = m a x ( 0 , x ) [x]_+=max(0, x) [x]+​=max(0,x)

     L t o t a l = L v a r + L d i s t L_{total}=L_{var}+L_{dist} Ltotal​=Lvar​+Ldist​

其中,各个参数表示如下:

  • C—— 表示车道线实例个数;
  • N c N_c Nc​—— 每个车道线实例中像素的个数;
  • u c u_c uc​—— 每个车道线实例的像素中心;
  • L v a r L_{var} Lvar​是方差损失,他的目的是为了降低类内距离
  • L d i s t L_{dist} Ldist​是距离损失,它的目的是增大类间距离 (不同车道线之间的距离);

网络结构图

LaneNet 的架构基于编码器 - 解码器网络 ENet,该网络是由 5 个阶段组成。前 3 个阶段是编码器网络,进行了两次下采样;后两个阶段是解码器网络,进行了两次上采样。
 

在这里插入图片描述


LaneNet 在该网络的基础上修改成了双分支网络。由于 ENet 的编码器比解码器包含更多的参数,完全在两个任务之间共享完整的编码器将导致不令人满意的结果。因此,LaneNet 只在两个分支之间共享前两个阶段 (1 和 2),留下 ENet 编码器的阶段 3 和完整的 ENet 解码器作为每个单独分支的主干。分割分支的最后一层输出单通道图像,用于二值化分割;而实例分割分支的最后一层输出 N 通道图像,其中 N 是实例维度。每个分支的损失项都是相等加权的,并通过网络反向传播。

1.4 H-Net 网络结构

LaneNet 网络输出的是每条车道线的像素集合,常规的处理是将图像转为鸟瞰图,然后用二次或三次多项式拟合出弯曲的车道线。然而,目前所使用的透视变换矩阵的参数通常是预先设定、不会改变的,在面对水平线波动的影响(如上下坡)等情况下的车道线拟合并不准确,鲁棒性不强。因此,作者提出了 H-net 模型,用来学习透视变换矩阵的参数 H。

在这里插入图片描述


H 有 6 个自由度,放置零是为了强制约束,即在变换下水平线保持水平。

H-NET 的网络体系结构较小,由 3x3 卷积、BN 层 和 Relu 的连续块构成。使用最大池化层来降低维度,并在最后添加 2 个全连接层。完整的网络结构如下图所示:
 

在这里插入图片描述


最后一个全连接层的结点数是 6,对应的就是 H 矩阵中的 6 个参数。

1.5 LaneNet 性能优点

检测速度。在英伟达 1080Ti 显卡上进行测试,检测一帧大小为 512x512 的彩色图片,耗时 19ms,因此每秒可处理 50 帧左右。
 

在这里插入图片描述


检测精度。 通过使用 LaneNet 结合三阶多项式拟合和 H-Net 的变换矩阵,在 tuSimple 挑战中检测精度达到 96.4%,获得了第四名,与第一名相比只有 0.5% 的差异。结果可以在下表中看到。

在这里插入图片描述

二、手把手带你实现 LaneNet

2.1 项目介绍

该项目在 github 上已经开源,获得了 1.3k 的星标,想试试的同学可克隆下来:https://github.com/MaybeShewill-CV/lanenet-lane-detection,如果打不开,也可以从我的百度云网盘下载:LaneNet 资料合集 ,提取码:1024

代码结构和各部分功能如下:

<span style="background-color:#f6f6f6"><span style="color:#333333"><code class="language-cpp">lanenet-lane-detection
├── config <span style="color:#6a737d">//配置文件</span>
├── <span style="color:#d73a49">data</span> <span style="color:#6a737d">//一些样例图片和曲线拟合参数文件</span>
├── data_provider <span style="color:#6a737d">// 用于加载数据以及制作 tfrecords</span>
├── lanenet_model 
│   ├── lanenet.py <span style="color:#6a737d">//网络布局 inference/compute_loss/compute_acc</span>
│   ├── lanenet_front_end.py <span style="color:#6a737d">// backbone 布局</span>
│   ├── lanenet_back_end.py <span style="color:#6a737d">// 网络任务和Loss计算 inference/compute_loss</span>
│   ├── lanenet_discriminative_loss.py <span style="color:#6a737d">//discriminative_loss实现</span>
│   ├── lanenet_postprocess.py <span style="color:#6a737d">// 后处理操作,包括聚类和曲线拟合</span>
├── model <span style="color:#6a737d">//保存模型的目录semantic_segmentation_zoo</span>
├── semantic_segmentation_zoo <span style="color:#6a737d">// backbone 网络定义</span>
│   ├── __init__.py
│   ├── vgg16_based_fcn.py <span style="color:#6a737d">//VGG backbone</span>
│   └─+ mobilenet_v2_based_fcn.py <span style="color:#6a737d">//mobilenet_v2 backbone</span>
│   └── cnn_basenet.py <span style="color:#6a737d">// 基础 block</span>
├── tools <span style="color:#6a737d">//训练、测试主函数</span>
│   ├── train_lanenet.py <span style="color:#6a737d">//训练</span>
│   ├── test_lanenet.py <span style="color:#6a737d">//测试</span>
│   └──+ evaluate_dataset.py <span style="color:#6a737d">// 数据集评测 accuracy</span>
│   └── evaluate_lanenet_on_tusimple.py <span style="color:#6a737d">// 数据集检测结果保存</span>
│   └── evaluate_model_utils.py <span style="color:#6a737d">// 评测相关函数 calculate_model_precision/calculate_model_fp/calculate_model_fn</span>
│   └── generate_tusimple_dataset.py <span style="color:#6a737d">// 原始数据转换格式</span>
├─+ showname.py <span style="color:#6a737d">//模型变量名查看</span>
├─+ change_name.py <span style="color:#6a737d">//模型变量名修改</span>
├─+ freeze_graph.py<span style="color:#6a737d">//生成pb文件</span>
├─+ convert_weights.py<span style="color:#6a737d">//对权重进行转换,为了模型的预训练</span>
└─+ convert_pb.py <span style="color:#6a737d">//生成pb文</span>
</code></span></span>

2.2 环境搭建

根据开源作者描述,其测试的环境为:

  • ubuntu 16.04
  • python3.5
  • cuda-9.0
  • cudnn-7.0
  • GTX-1070 GPU
  • tensorflow 1.12.0

我使用的环境与配置为:

  • ubuntu16.04 系统
  • PyCharm 2020
  • python3.6
  • tensorflow1.13.1-gpu
  • cuda-10.0
  • cudnn7.6.4
  • opencv4.0.0
  • RTX 2070 GPU

想尝试的朋友,可以参考上面两种配置,也可以自行尝试其他的版本。

2.3 准备工作

如果想要自行训练的同学,可以下载 TuSimple 数据集,进行训练。同样,我们也可以直接使用官方训练好的模型,来输入图片,看看测试效果。为了方便,下面我们直接加载已经训练好的模型,进行本地测试。

(1) 下载 TuSimple 数据集,如果不训练可以跳过这一步。

(2) 下载训练好的模型,下载链接:LaneNet 资料合集 ,提取码:1024

下载完后,我们将模型文件 tusimple_lanenet 放在工程目录下的 model 文件中,如下图所示:

在这里插入图片描述

2.4 模型测试

完成环境配置和模型部署后,我们就可以进行测试了!

(1) 先对 TusSample 数据集中的图片进行测试

  • 第一步,在原工程目录下的 data 文件中新建一个 Mytest 文件夹,然后任意选取 TusSample 数据集中的一张图片放入其中,例如 1.jpg,如下图所示:

在这里插入图片描述

  • 第二步,使用 PyCharm 打开下载好的项目工程,配置好环境后,打开终端,如下图所示:

在这里插入图片描述

  • 第三步,在终端输入以下命令,执行程序:
<span style="background-color:#f6f6f6"><span style="color:#333333"><code class="language-cpp"><span style="color:#6f42c1">python</span> <span style="color:#032f62">tools</span><span style="color:#032f62">/</span><span style="color:#032f62">test_lanenet</span><span style="color:#032f62">.</span><span style="color:#032f62">py </span><span style="color:#032f62">--</span><span style="color:#032f62">weights_path model</span><span style="color:#032f62">/</span><span style="color:#032f62">tusimple_lanenet</span><span style="color:#032f62">/</span><span style="color:#032f62">tusimple_lanenet</span><span style="color:#032f62">.</span><span style="color:#032f62">ckpt </span><span style="color:#032f62">--</span><span style="color:#032f62">image_path data</span><span style="color:#032f62">/</span><span style="color:#032f62">Mytest</span><span style="color:#032f62">/</span><span style="color:#032f62">1.</span><span style="color:#032f62">jpg</span>
</code></span></span>

最后车道线检测效果如下:

在这里插入图片描述

(2)对自己的图片进行测试

  • 第一步,选择自己拍摄的一张车道线图片 2.jpg,放入刚才新建好的 Mytest 文件夹下,如下图所示:

在这里插入图片描述


第二步,打开终端,输入命令,执行程序:

<span style="background-color:#f6f6f6"><span style="color:#333333"><code class="language-cpp"><span style="color:#6f42c1">python</span> <span style="color:#032f62">tools</span><span style="color:#032f62">/</span><span style="color:#032f62">test_lanenet</span><span style="color:#032f62">.</span><span style="color:#032f62">py </span><span style="color:#032f62">--</span><span style="color:#032f62">weights_path model</span><span style="color:#032f62">/</span><span style="color:#032f62">tusimple_lanenet</span><span style="color:#032f62">/</span><span style="color:#032f62">tusimple_lanenet</span><span style="color:#032f62">.</span><span style="color:#032f62">ckpt </span><span style="color:#032f62">--</span><span style="color:#032f62">image_path data</span><span style="color:#032f62">/</span><span style="color:#032f62">Mytest</span><span style="color:#032f62">/</span><span style="color:#032f62">2.</span><span style="color:#032f62">jpg</span>
</code></span></span>

对自己的拍摄的图片检测效果如下:

在这里插入图片描述


测试分析:

从图中可以看出,对自己的图片进行检测时,最终的检测结果虽然能够完美地与实际车道线重合,但是延伸至了空中。

产生这种情况最主要的原因是:没有自己制作数据集进行训练,从而得到更有针对性的模型造成的。由于这里我使用的测试模型是在 TuSimple 数据集下训练得到的,所以我们对 TuSimple 中的图片测试效果会很好,比如前面的 1.jpg。

如果我们想要对自己的图片进行测试,得到更好的效果,那么就需要自己的数据集。比较好的办法是:

  • 首先在 TuSimple 数据集下进行训练,得到的训练模型作为预训练模型,这一部分工作其实已经做好了,大家直接下载预训练模型即可
  • 然后,在预训练模型的基础上,加载自己制作的数据集,再进行训练,直到达到预期的效果。

采用这种迁移学习的思想,往往能够事半功倍!

  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要使用STM32CubeMX、LAN8720、LwIP和FreeRTOS实现网络通信,需要注意以下几点。 首先,STM32CubeMX是一个图形化配置工具,用于为STM32微控制器生成初始化的代码框架。我们可以通过选择所需的外设(如以太网控制器)和配置参数来生成代码。 其次,LAN8720是一个用于实现以太网通信的PHY(物理层)芯片,负责将数据从媒介访问控制层(MAC层)转换为物理传输信号。 接下来,LwIP(Lightweight IP)是一个轻量级的网络协议栈,用于实现TCP/IP协议。我们需要将LwIP集成到项目中,并配置好网络参数,如IP地址、子网掩码和网关。 最后,FreeRTOS是一个流行的实时操作系统,用于管理任务调度和资源管理。我们可以将网络通信任务添加到FreeRTOS的任务列表中,并通过队列和信号量等机制进行任务间通信和同步。 总体实现步骤如下: 1. 使用STM32CubeMX选择并配置以太网控制器和PHY,并生成初始化代码。 2. 配置LwIP的网络参数,如IP地址、子网掩码和网关。 3. 将LwIP集成到项目中,包括源代码和相应的头文件。 4. 添加网络通信任务到FreeRTOS的任务列表中。 5. 在网络任务中,使用LwIP提供的API进行网络初始化、连接设置以及数据收发等操作。 6. 通过使用队列或信号量等机制,实现不同任务间的数据共享和同步。 7. 在主函数中初始化FreeRTOS,并启动任务调度器。 通过以上步骤,我们可以利用STM32CubeMX、LAN8720、LwIP和FreeRTOS实现网络通信功能。这样我们就可以在STM32微控制器上实现网络连接、数据传输等网络应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值