2D车道线检测算法总结

article/2025/10/2 4:40:42

关于2D车道线检测算法的总结主要分为两类:一类基于语义分割来做,一类基于anchor和关键点来做。还有基于曲线方程来做的,但是落地的话还是上面两种为主。

一、基于语义分割的车道线检测算法

1.LaneNet

论文创新点:

1.将车道线检测看作一个实例分割问题,在网络里除了语义分割头,还有一个embedding头用来聚类实例的。

2.通过embedding向量和聚类的后处理,使得模型可以检测很多车道线(没有先验个数限制)。

 模型结构

backbone+2个head,一个是语义分割头,一个是聚类头。根据语义分割得到哪些像素是车道线,然后再根据聚类头的向量,使用聚类算法对车道线像素进行实例化。得到实例化后进行拟合。论文里使用的聚类算法是meanshift,后续开源代码里有用DBSCAN的,但是他们的耗时都很多,无法满足上车需求。

LOSS的使用

为了均衡正负样本比例,语义分割loss使用的加权交叉熵损失计算。

聚类分支loss使用的var loss和dist loss组成,var使得同类之间靠拢,dist使得不同类的中心相互远离彼此。

2.SCNN

传统的网络是在层与层之间进行卷积,长宽同样的进行信息聚集,并没有很好的利用车道线的形状先验。本论文提出了Spatial CNN,其在一层特征图上按照上下左右的方向有顺序的进行切片卷积,从而使网络可以更好地提取车道线特征。

 

 上图中(a)是训练流程,(b)是推理流程。看到论文里假设最多有四条车道线。对于存在值大于0.5的每个车道标记,我们每隔20行搜索相应的概率图,以获得响应最高的位置。然后通过三次样条函数连接这些位置,这是最终的预测。

代码分析

    def message_passing_forward(self, x):self.message_passing = nn.ModuleList()# 从上到下,使用 1*8的卷积。self.message_passing.add_module('up_down', nn.Conv2d(128, 128, (1, ms_ks), padding=(0, ms_ks // 2), bias=False))# 从下到上也是 1*8self.message_passing.add_module('down_up', nn.Conv2d(128, 128, (1, ms_ks), padding=(0, ms_ks // 2), bias=False))self.message_passing.add_module('left_right',nn.Conv2d(128, 128, (ms_ks, 1), padding=(ms_ks // 2, 0), bias=False))self.message_passing.add_module('right_left',nn.Conv2d(128, 128, (ms_ks, 1), padding=(ms_ks // 2, 0), bias=False))Vertical = [True, True, False, False]Reverse = [False, True, False, True]# 对四个方向进行遍历for ms_conv, v, r in zip(self.message_passing, Vertical, Reverse):x = self.message_passing_once(x, ms_conv, v, r)return xdef message_passing_once(self, x, conv, vertical=True, reverse=False):"""Argument:----------x: input tensorvertical: vertical message passing or horizontalreverse: False for up-down or left-right, True for down-up or right-left"""nB, C, H, W = x.shapeif vertical: #如果是竖直方向,则沿着H进行切片# 得到一个长为H的数组,里面的元素维度[B, C, 1, W]slices = [x[:, :, i:(i + 1), :] for i in range(H)]dim = 2else: #如果是横向,则沿着W进行切片,得到一个长为W的数组,里面的元素维度[B, C, H, 1]slices = [x[:, :, :, i:(i + 1)] for i in range(W)]dim = 3if reverse:slices = slices[::-1]out = [slices[0]] #第一个切片不操作for i in range(1, len(slices)):out.append(slices[i] + F.relu(conv(out[i - 1]))) #当前切片 等于当前值+前一个切片卷积完的结果if reverse:out = out[::-1]return torch.cat(out, dim=dim)

通过代码分析我们看到,其对切片进行遍历,当前切片的特征是由前一层切片卷积后+当前切片的原始特征得到的,所以是顺序执行的,这样的计算非常耗时。于是引出下一篇文章RESA。

3.RESA

(91条消息) RESA车道线路沿检测_CVplayer111的博客-CSDN博客

这个代码里RESA采用的并行计算,所有切片同时+前面的切片卷积激活结果。这样直接x[...,idx,.]就行,不用像SCNN里生成切片数组。一个一个顺序进行。同时还提出了双边上采样结构,upsample双线性插值得到粗粒度特征,转置卷积得到细粒度特征。

4.LaneAF

(91条消息) LaneAF论文解读和代码讲解_CVplayer111的博客-CSDN博客

将传统聚类后处理去掉,根据模型预测的方向向量来实例化像素点,生成的一维HAF进行行像素分类,然后根据二维的VAF进行不同行之间的关联。

二、基于anchor和关键点的车道线检测算法

1. UFSA

首先论文分析了当前基于语义分割算法的痛点,每个点都预测分辨率太大,耗时严重导致速度慢,同时其感受野有限,只有局部的感受野,对于车道线模糊,遮挡问题不好。

论文将车道线检测问题转化为Row anchors上的分类问题,Row anchors是预定的行位置,论文里是18个行anchor。每一行都被划分为许多单元格,车道线检测就变为在行anchor上选择单元格。

 其中h表示行数,w表示每行多少个网格,都是人为设定的。远小于原图像的H*W,所以计算效率大大提升。比如我们设定网络可以检测c个车道线,那么语义分割的复杂度是 (c+1)*H*W,而我们的是(w+1)*c*h.  

损失函数方面,加入了结构损失,用相邻行差值来约束车道线的光滑性,用二阶差分来约束车道线是直线。 

 网络结构如图所示,加入了语义分割的辅助分支,在推理的时候去掉,主要为了实现主干网络全局和局部信息的聚合。骨干网络后加入FC层,然后再reshape成h*w的形状进行预测。

算法缺陷:只能预测固定的数量车道线,同时只能检测纵向的车道线,其他方向就不行,因为结构损失约束。

2.FOLOLane

是一种基于关键点检测的方法,将车道线检测看作局部的几何建模。论文指出以往的聚类后处理使得推理非常复杂,同时像素级的曲线拟合是冗余的和有噪声的。

 图片经过CNN处理,得到四个特征图,一个heatmap用来预测关键点出现的概率,其余三个用来预测当前点,上面的,下面的三个关键点的x偏移。在训练时,将每个车道线标注的点插值成连续的像素点,使用未归一化的高斯核对这些点周围的像素点处理。计算focalloss时,只有等于1的才是正样本。此时把图像沿着高度方向等间距画线,距离为固定值y,,等分线与刚才插值得到的像素点的交点称为关键点,对于这个关键点来说,模型预测三个偏移值,一个是这个关键点的偏移,另外两个是与其间隔y的两个点的偏移。已知当前关键点,就可以求出上下两个关键点。上下关键点偏移的loss计算是:

 相当于根据P关键点的坐标+与其预测的间隔y的两个关键点偏移,得到这两个点的预测坐标,求预测坐标与GT坐标的x偏移。对于当前点的x偏移loss公式如下:

 这个我不太懂啥意思,到时候看代码。

有了上面的预测结果,如何来解码全局的车道线结构。论文中给了两种方法,一种是精细的计算方法,耗时,一种是简单的计算方法。我主要介绍简单的计算方法。

1.先以等间距y画好线,所有线上具有最高响应的点组成current key_point

2.根据三个偏移计算相关点

3.current key_point集合内部建立相关性,根据当前行关键点预测的上下行的关键点与上下行的current key_point求距离,离的最近就是关联的。

4.从具有最多current key_point的行开始,根据3建立相关性,不断的向两边关联,组成一个group,然后再根据x横向偏移对关键点的x坐标进行修正。

3.LaneATT

基于anchor的车道线检测算法,速度特别快。同时提出了一种基于anchor的注意力机制

 首先图片经过backbone得到图像特征,然后根据anchor对特征进行池化,得到每个anchor的局部特征,随后经过一个FC和softmax与其他的anchor做注意力机制,得到全局特征,全局特征与局部特征相加,进行分类和预测。

 anchor定义

使用起始点x0,y0和角度来表示anchor,起始点从图像边界出发,在左右下三个边界共有2782个anchor,训练时,我们统计其为正样本的次数,选取前1000个,在推理时就用这1000个。

车道线定义

沿图像纵向做等分操作,得到等分点72个,对于这72个固定的y,因此72个对应x就决定了不同车道线的差异,因为车道线不会贯穿整个图像,所以会有一个s和e表示x的起始终止范围,也就是车道线的有效范围。

anchor_pooling池化操作

对于每一个anchor都要从图像特征里聚合特征,特征图宽度为H_{F},那么从0到Hf-1有Hf个y坐标,根据anchor的起始点和角度,可以得到H_{F}个xy点,得到anchor特征a_{i}^{loc}\epsilon R^{C_{F}*H_{F}},有些点的xy不在特征图里,那么其特征在a_{i}^{loc}里为0。

注意力机制

anchor_pooling之后得到的特征向量是局部特征,于是论文提出一个注意力机制来产生一个全局特征。每一个anchor的特征经过FC和softmax求得与其他anchor的权重,这个过程可以并行计算。

 

 每个anchor全局特征的维度[CF,HF],和局部特征一样,可以直接concate。

预测头

concate之后送入两个全连接层,一个用于分类,k个车道线类别+1个背景,输出一个K+1维的向量。一个用于回归,输出一个L长度和72个x的偏移。

NMS后处理

 计算两x公共范围里的点的距离,用这个距离对网络预测的车道线进行NMS操作。在训练时正负样本的定义也是根据anchor和GT的这个距离来定义,大于多少的为负样本,小于多少的为正样本。

4.CLRNet


http://chatgpt.dhexx.cn/article/LFYxs6Ok.shtml

相关文章

车道线检测-Eigenlanes 论文学习笔记

论文:《Eigenlanes: Data-Driven Lane Descriptors for Structurally Diverse Lanes》 代码:https://github.com/dongkwonjin/Eigenlanes 核心:在 Eigenlane Space 中检测车道线 创新点 Eigenlane:数据驱动的车道描述符&#xff…

OpenCV的车道线检测

资源下载地址:https://download.csdn.net/download/sheziqiong/85604275 资源下载地址:https://download.csdn.net/download/sheziqiong/85604275 final_mark.py是最终,前面的都是一部分一部分测试的功能,用的是霍夫变换拟合&…

动手学无人驾驶(7):车道线检测

最近在研究视觉语义地图,需要进行车道线检测,发现这篇车道线检测论文效果蛮好的 (Ultra Fast Structure-aware Deep Lane Detection)。论文作者在知乎上已经介绍过了:https://zhuanlan.zhihu.com/p/157530787&#xff…

高级车道线检测

基于图像处理相关技术的高级车道线检测(可适用于弯道,车道线颜色不固定,路面阴影,亮光) pipeline: 1.校准摄像头的畸变,使拍摄照片能够较完整的反映3D世界的情况 2.对每一帧图片做透视转换(pers…

传统方法车道线标注及相关知识

目录 一、图像二值化处理 1.Sobel算子绝对值 2.Sobel算子 3.倾斜角度 4.HLS颜色空间 5.二值图结合 二、车道线分割 1.仿射变换 2.车道线直方图 3.滑动窗口寻找车道线 4.车道线拟合 5.车道线区域标注 一、图像二值化处理 主要目的是通过二值化图像,使得车…

学习笔记之车道线相关记录

一. 车道线相关的知识 &&1.标线的分类 以下分类来自于百科: 按照道路交通标线的功能划分为:指示标线、警告标线和禁止标线。 按标划方法可分为:白色虚线、白色实线、黄色虚线、黄色实线、双白虚线、双白实线、双黄虚线和双黄实线…

关于python 最简单封装实例

一、 #定义一个类 class Person: #init是定义类实例初始化函数 ,没有返回return def __init__(self,name,area): self.name name self.area area #类里面定义方法 def run(self): print(self.name) …

Python软件封装打包

作者:Naples 链接:https://www.zhihu.com/question/32703639/answer/165326590 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 Python Tkinter打包封装的方法有:PyInstaller, py…

Python封装、继承和多态

Python 语言在设计之初,就定位为一门面向对象的编程语言,“Python 中一切皆对象”。同时,Python 也支持面向对象的三大特征:封装、继承和多态。 一、封装 封装(Encapsulation),即在设计类时&am…

python程序封装

python程序封装1 报错请执行pip install --upgrade setuptools 和 pip install --upgrade wheel 步骤如下: (1)安装pyinstaller,可以直接在cmd命令行中,输入命令“pip install pyinstaller”,安装pyinsta…

python封装程序

#终端/cmd命令下: 1.安装python Welcome to Python.org 2.安装pip pip PyPI 下载get-pip.py 在cmd窗口下执行,python */*/get-pip.py(*为文件所在位置) *如果安装好后出现 不是内部命令的情况 需要在环境中添加&#xff…

制作python包,封装成可用模块

制作python包,封装成可用模块 首先编写py程序: printtest.py #coding: utf-8 def test():print(print test)if __name__ __main__:test() 将以上.py文件做成python模块,需要在相同目录下创建setup.py文件,setup.py中输入配置信息: #cod…

Python 程序封装-打包成exe程序

Python 程序封装-打包成exe程序 前言一、 Python 打包工具—Pyinstaller二、打包具体过程1. 打包成仅包含一个独立的exe程序2. 打包成包含文件夹的程序,内有相关的依赖库(推荐)3. 其他的打包命令 三、注意事项 欢迎学习交流! 邮箱…

怎么python程序封装?此文详解

python程序封装1 步骤如下: (1)安装pyinstaller,可以直接在cmd命令行中,输入命令“pip install pyinstaller”,安装pyinstaller (2)进入py代码的保存目录,这里py代码放在“E:\python学习\python_work” (3)cmd,输入命令:e:,进入e盘 (4)继续输入:E:\pytho…

Python封装

在用新电脑做python的封装的时候,出现了一系列的问题。在这里简单写一下Python的封装的一些流程以及可能出现的问题和解决方法吧。 封装我选择的是pyinstaller 首先是安装pyinstaller:Python 默认并不包含 PyInstaller 模块,因此需要自行安…

python之类的封装

博主简介:原互联网大厂tencent员工,网安巨头Venustech员工,阿里云开发社区专家博主,微信公众号java基础笔记优质创作者,csdn优质创作博主,创业者,知识共享者,欢迎关注,点赞&#xff…

Python入门——函数封装

当工程量比较大时,我们可以采取“函数封装”的方法实现函数的重复使用,避免“重复造轮子”。 步骤 手动创建一个包,只需进行以下 2 步操作: 新建一个文件夹,文件夹的名称就是新建包的包名;在该文件夹中&…

Python学习基础笔记五十八——封装

封装:广义上的面向对象封装。代码的保护。面向对象的思想本身就是一种封装,只让自己的对象能调用自己类中的方法。 狭义的封装概念:面向对象的三大特性之一:让属性和方法都藏起来,不让你看见。 例1: clas…

Python必备封装基本代码~Python函数

大家好,我是辣条 最近不少粉丝通过文末找到辣条让我分享一些代码封装这一块的内容,今天他来了~ 一遍看不懂就收起来慢慢看,我写的还是很详细的,一定是能轻松拿捏住Python函数的,不过还请记得多多支持辣条,…

PMP学习笔记顺口溜

区分几种组织结构 老板项目为系统; 只有职能为职能; 多个部门多部门, 多个项目为项目 职能项目为矩阵,项强为强,项弱为弱; 项目职能一般大 :平衡 网络分散为虚拟