浙江大学的一篇工作。可以直接看原作者的中文介绍:
https://zhuanlan.zhihu.com/p/157530787
官方源码:
https://github.com/cfzd/Ultra-Fast-Lane-Detection
这里主要是记录一下自己的学习,同时对官方源码进行了解读。下面是正文:
摘要
现今主流做法将车道检测当作语义分割问题来处理,但这样存在复杂场景下效果不好、速度慢的缺点。受人类感知的启发,在严重遮挡和极端光照条件下对车道的识别主要基于上下文和全局信息。具体来说,我们将车道检测过程视为使用全局特征的基于行的选择问题。
contributions:
- 减少了计算量
- 基于全局特征的大的感受野能够处理复杂场景(遮挡、光照等)
- 结构化损失
- 速度超快
引言
相关工作
传统方法。
深度学习方法。
方法
车道检测的新范式
快速和没有视觉线索对车道检测十分重要。在本节中,我们通过解决速度和无视觉线索的问题来展示我们的范式的派生。 为了更好地说明,表1显示了下文中使用的一些符号。
范式定义
代码解读
安装
- git clone源码
git clone https://github.com/cfzd/Ultra-Fast-Lane-Detection
cd Ultra-Fast-Lane-Detection
- 创建conda虚拟环境并激活
conda create -n lane-det python=3.7 -y
conda activate lane-det
- 安装依赖
#If you dont have pytorch
conda install pytorch torchvision cudatoolkit=10.1 -c pytorch
pip install -r requirements.txt
- 数据准备
下载CULane
和Tusimple
。 然后将它们提取到$ CULANEROOT
和$ TUSIMPLEROOT
。 Tusimple
的目录排列应如下所示:
$TUSIMPLEROOT
|──clips
|──label_data_0313.json
|──label_data_0531.json
|──label_data_0601.json
|──test_tasks_0627.json
|──test_label.json
|──readme.md
CULane
的目录排列应如下所示:
$CULANEROOT
|──driver_100_30frame
|──driver_161_90frame
|──driver_182_30frame
|──driver_193_90frame
|──driver_23_30frame
|──driver_37_30frame
|──laneseg_label_w16
|──list
对Tusimple
数据集,未提供语义分割标签,因此我们需要根据json文件生成。
python scripts/convert_tusimple.py --root $TUSIMPLEROOT
#this will generate segmentations and two list files: train_gt.txt and test.txt
import os
import cv2
import tqdm
import numpy as np
import pdb
import json, argparse
def calc_k(line):
'''
Calculate the direction of lanes
'''
line_x = line[::2]
line_y = line[1::2]
length = np.sqrt((line_x[0]-line_x[-1])**2 + (line_y[0]-line_y[-1])**2)
if length < 90:
return -10 # if the lane is too short, it will be skipped
p = np.polyfit(line_x, line_y,deg = 1)
rad = np.arctan(p[0])
return rad
def draw(im,line,idx,show = False):
'''
Generate the segmentation label according to json annotation
'''
line_x = line[::2]
line_y = line[1::2]
pt0 = (int(line_x[0]),int(line_y[0]))
if show:
cv2.putText(im,str(idx),(int(line_x[len(line_x) // 2]),int(line_y[len(line_x) // 2]) - 20),cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), lineType=cv2.LINE_AA)
idx = idx * 60
for i in range(len(line_x)-1):
cv2.line(im,pt0,(int(line_x[i+1]),int(line_y[i+1])),(idx,),thickness = 16)
pt0 = (int(line_x[i+1]),int(line_y[i+1]))
def get_tusimple_list(root, label_list):
'''
Get all the files' names from the json annotation
'''
label_json_all = []
for l in label_list:
l = os.path.join(root,l)
label_json = [json.loads(line) for line in open(l).readlines()]
label_json_all += label_json
names = [l['raw_file'] for l in label_json_all]
h_samples = [np.array(l['h_samples']) for l in label_json_all]
lanes = [np.array(l['lanes']) for l in label_json_all]
line_txt = []
for i in range(len(lanes)):
line_txt_i = []
for j in range(len(lanes[i])):
if np.all(lanes[i][j] == -2):
continue
valid = lanes[i][j] != -2
line_txt_tmp = [None]*(len(h_samples[i][valid])+len(lanes[i][j][valid]))
line_txt_tmp[::2] = list(map(str,lanes[i][j][valid]))
line_txt_tmp[1::2] = list(map(str,h_samples[i][valid]))
line_txt_i.append(line_txt_tmp)
line_txt.append(line_txt_i)
return names,line_txt
def generate_segmentation_and_train_list(root, line_txt, names):
"""
The lane annotations of the Tusimple dataset is not strictly in order, so we need to find out the correct lane order for segmentation.
We use the same definition as CULane, in which the four lanes from left to right are represented as 1,2,3,4 in segentation label respectively.
"""
train_gt_fp = open(os.path.join(root,'train_gt.txt'),'w')
for i in tqdm.tqdm(range(len(line_txt))):
tmp_line = line_txt[i]
lines = []
for j in range(len(tmp_line)):
lines.append(list(map(float,tmp_line[j])))<