近期参与到了手写AI的车道线检测的学习中去,以此系列笔记记录学习与思考的全过程。车道线检测系列会持续更新,力求完整精炼,引人启示。所需前期知识,可以结合手写AI进行系统的学习。
OpenLane是迄今为止第一个真实世界和最大规模的3D车道数据集。OpenLane包含20万帧、超过88万条实例级车道、14个车道类别(单白色虚线、双黄色实体、左/右路边等),以及场景标签和路线邻近目标(CIPO)注释。详见论文。
OpenLane数据集是在自动驾驶领域的主流数据集上构建的。在1.0版本中,在Waymo开放数据集上发布了注释。OpenLane数据集侧重于车道检测和CIPO。我们注释了每一帧中的所有车道,如果中间没有路边,则包括相反方向的车道。除了车道检测任务,我们还注释:(a)场景标签,例如天气和位置;(b)CIPO,被定义为最受关注的目标w.r.t. ego车辆;除了感知的一整套对象之外,这样的标签对于随后的模块(如规划/控制)是非常实用的。
- 必要的高质量 2D 车道标签。它们包含跟踪 ID、类别和 2D 点地面实况的最终注释。
- 然后,对于每一帧,点云首先使用原始 3D 对象边界框进行过滤,然后投影回相应的图像中。我们进一步将与 2D 车道相关的点保留在一定的阈值内。
- 在定位和地图系统的帮助下,段内帧中的 3D 车道点可以拼接成长的、高密度的车道。
- 2D 投影高于其 2D 注释结束位置的点被标记为不可见。
- 最终部署平滑步骤来过滤任何异常值并生成 3D 标记结果。
我们用下面的格式注释车道线。
- 车道形状。每个2D/3D车道被表示为一组2D/3D点。
- 车道类别。每个车道都有一个类别,如双黄线或路缘。
- 车道属性。一些车道具有诸如右、左的属性。
- 车道追踪ID。除路缘外,每条车道都有唯一的id。
- 停车线和路缘。
Lane Annotation的 .json 文件中包含相机内参、外参、车道线类别、每个点的可见性、像素坐标系下点的2D坐标(u, v)、相机坐标系下点的3D坐标(x, y, z)、车道的左右属性、车道的跟踪ID以及文件的相对路径。lane_lines中有k条车道线,对应k组内容数据。
{
"intrinsic": <float> [3, 3], -- 摄像机的内参矩阵,描述了摄像机的几何和光学特性如焦距、光心位置等
"extrinsic": <float> [4, 4], -- 摄像机的外参矩阵,描述了摄像机相对于世界坐标系的位置和姿态
"lane_lines": [ -- 包含多条车道线的信息列表
{
"category": <int>, -- 车道线的类别,如白色虚线、白色实线、双白虚线等
0: 'unkown',
1: 'white-dash',
2: 'white-solid',
3: 'double-white-dash',
4: 'double-white-solid',
5: 'white-ldash-rsolid',
6: 'white-lsolid-rdash',
7: 'yellow-dash',
8: 'yellow-solid',
9: 'double-yellow-dash',
10: 'double-yellow-solid',
11: 'yellow-ldash-rsolid',
12: 'yellow-lsolid-rdash',
20: 'left-curbside',
21: 'right-curbside'
"visibility": <float> [n, ], -- 每个点的可见性,通常用于标记哪些点是可见或被遮挡的
"uv": [ -- 在图像坐标下的车道线坐标
[u1,u2,u3...], -- U坐标列表
[v1,v2,v3...] -- V坐标列表
],
"xyz": [ -- 在摄像机坐标下的车道线坐标
[x1,x2,x3...], -- X坐标列表
[y1,y2,y3...], -- Y坐标列表
[z1,z2,z3...] -- Z坐标列表
],
"attribute": <int>, -- 车道线的左右属性,例如左-左、左、右、右-右
1: left-left
2: left
3: right
4: right-right
"track_id": <int> -- 车道线的跟踪ID,用于跟踪同一车道线在不同帧中的连续性
},
...
],
"file_path": <str> -- 图像的文件路径
}
- 车道经常被物体遮挡或因磨损而看不见,但它们对于实际应用仍然有价值。因此,如果车道的部分可见,我们会对车道进行注释,这意味着根据上下文,一侧被遮挡的车道将被延长,或者中间部分不可见的车道将被完成。
- 可见度主要与远处的点有关,而不是遮挡或磨损。评估中不需要它,但它可以帮助模型区分可见车道点和不可见车道点。
- 车道数量变化是很常见的,特别是当车道具有复杂拓扑时,例如合并和分流情况下的分叉车道。叉车道被注释为具有共同起点(分割)或终点(合并)的单独车道 - 车道检测方法需要两个紧密相邻的车道。
- 我们将每个车道注释为 14 个车道类别之一。请注意,如果交通护柱不是临时放置的,则也被视为路边
- 我们为每个车道标注了一个跟踪 ID,该 ID 在整个路段中是唯一的。我们相信这可能有助于视频车道检测或车道跟踪任务。
我们还根据最重要的 4 条车道与自我车辆的相对位置,为它们分配 1-4 中的编号。基本上,左右车道为1,左侧车道为2,右侧车道为3,左右车道为4。- 我们根据这些主题提供不同的拆分:上下案例、曲线案例、极端天气案例、夜间案例、交叉案例和合并&拆分案例。 Up&Down 案例重点关注上坡/下坡道路。曲线情况由不同的大曲线道路组成。极端天气,顾名思义,是由雨中的道路组成的。夜间箱针对光线昏暗的道路。交叉路口情况和合并&分割情况是车道拓扑困难的两种常见交通场景。
最终可以获得:
我们用下面的格式注释CIPO和场景。
- 具有代表对象重要性级别的类别的2D Bounding Box。
- 场景标签。它描述了在何种情况下收集该帧。
- 天气标签。它描述了在什么天气下收集该帧。
- 小时标签。它标注了该帧是在什么时间收集的。
我们利用Waymo开放数据集中的2D边界框注释来生成CIPO注释。为了涵盖复杂的场景,我们将对象(主要包括车辆、行人和骑自行车的人)分为 4 个不同的 CIPO 级别。
- 级别1:在所需的反应距离内最接近自我车辆,并且有超过50%的部分在自我车道上。级别 1 最多包含一个对象。
- 级别2:身体与自我通道的真实或虚拟线条相互作用的物体,通常在切入或切出的过程中。
- 级别3:主要在反应距离或可驾驶区域内的物体,或位于左/自我/右车道内的物体,遮挡率小于50%。请注意,相反方向的车辆也可以处于此 CIPO 级别。
- 级别4:几乎不太可能影响未来道路的遗骸。它们主要是远距离车道中的物体、可驾驶区域以外的物体或我们数据集中停放的车辆。
{
"results": [ -- 结果列表,包含多个cipo对象的信息
{
"width": <float>, -- cipo边界框的宽度
"height": <float>, -- cipo边界框的高度
"x": <float>, -- cipo边界框左上角的x坐标
"y": <float>, -- cipo边界框左上角的y坐标
"id": <str>, -- cipo的重要性级别
"trackid": <str>, -- cipo的跟踪ID,整个片段中唯一
"type": <int>, -- cipo的类型,如未知、车辆、行人、标志、骑行者等
0: TYPE_UNKNOWN
1: TYPE_VEHICLE
2: TYPE_PEDESTRIAN
3: TYPE_SIGN
4: TYPE_CYCLIST
},
...
],
"raw_file_path": <str> -- 图像的文件路径
}
{
"segment-xxx": <str> -- segment id
{
"scene": <str>
"weather": <str>
"time": <str>
}
... (1000 segments)
}
- scene:住宅、城市、郊区、高速公路、停车场
- weather:晴朗, 部分云, 阴, 雨, 有雾
- time:白天,夜晚,黎明/黄昏
最后可以得到:
- **Google Drive:**https://drive.google.com/drive/folders/18upnDfB-VVuQf3GPiv_JQn1-BUOcAotk?usp=sharing
- 百度云(直接将网址粘贴到浏览器中):https://pan.baidu.com/s/ 14Mbo1u6VndFl6O7aeEW9SQ?pwd=t6h6
- OpenDateLab: https: //opendatalab.org.cn/OpenLane
from openxlab.dataset import dataset_get
import openxlab
openxlab.login(ak="6eg34zgvrkye9yg2jx91",
sk="orjrgbdlkq1j8klwr20jm7gxewyw2vmm47eqxvpd", re_login=True)
dataset_get(dataset_repo_name='OpenDriveLab/OpenLane',
destination_path='/media/wanj/MSSD1/OpenSourceDataset/Openlane/') # destination_path:下载文件指定的本地路径
标注json 文件中每一行包括三个字段
raw_file : 每一个数据段的第20帧图像的的 path 路径
lanes 和 h_samples 是数据具体的标注内容,为了压缩,h_sample 是纵坐标(应该是从上到下拍好顺序的),lanes 是每个车道的横坐标,是个二维数组。
-2 表示这个点是无效的点
上面的数据就有 4 条车道线,第一条车道线的第一个点的坐标是(632,280)。
标注的过程应该是,将图片的下半部分如70%*height 等分成N份。然后取车道线(如论虚实)与该标注线交叉的点
利用以下脚本可以处理得到标注的数据,这个脚本稍微改动下也可以作为深度学习输入的图像。
# -*- coding: utf-8 -*-
import cv2
import json
import numpy as np
# 设置基础路径
base_path = "/Users/jcl/workspace/lane_detection/"
# 打开 JSON 格式的标签文件
file=open(base_path+'test_label.json','r')
image_num=0
# 逐行读取 JSON 文件
for line in file.readlines():
# 将 JSON 行转换成字典
data=json.loads(line)
# 如果是第 29 帧,进行处理
if image_num == 29:
# 读取相应的原始图像
image=cv2.imread(base_path+data['raw_file'])
# 初始化二进制图像数组,用于存储车道线的二值图像
binaryimage=np.zeros((image.shape[0],image.shape[1],1),np.uint8)
# 初始化实例图像数组,用于存储每条车道线的实例
instanceimage=binaryimage.copy()
# 获取车道线的横坐标和纵坐标
arr_width=data['lanes']
arr_height=data['h_samples']
width_num=len(arr_width)
height_num=len(arr_height)
# 遍历车道线的纵坐标
for i in range(height_num):
lane_hist=40 # 用于实例图像中不同车道的区分,每条车道加 50
# 遍历各车道线的横坐标
for j in range(width_num):
# 检查坐标是否有效,并在图像上标记
if arr_width[j][i-1]>0 and arr_width[j][i]>0:
binaryimage[int(arr_height[i]),int(arr_width[j][i])]=255
instanceimage[int(arr_height[i]),int(arr_width[j][i])]=lane_hist
# 若前一个点也有效,画线连接两点
if i>0:
cv2.line(binaryimage, (int(arr_width[j][i-1]),int(arr_height[i-1])), (int(arr_width[j][i]),int(arr_height[i])), 255, 10)
cv2.line(instanceimage,(int(arr_width[j][i-1]),int(arr_height[i-1])), (int(arr_width[j][i]),int(arr_height[i])), lane_hist, 10)
lane_hist+=50
# 显示原始图像和生成的二值图与实例图
cv2.imshow('image.jpg',image)
cv2.waitKey()
cv2.imshow('binaryimage.jpg',binaryimage)
cv2.waitKey()
cv2.imshow('instanceimage.jpg',instanceimage)
cv2.waitKey()
break
# 保存生成的图像
# string1=base_path+"gt_image_binary/"+str(image_num)+".png"
# string2=base_path+"gt_image_instance/"+str(image_num)+".png"
# string3=base_path+"raw_image/"+str(image_num)+".png"
# cv2.imwrite(string1,binaryimage)
# cv2.imwrite(string2,instanceimage)
# cv2.imwrite(string3,image)
image_num = image_num + 1
file.close()
print "total image_num:"+str(image_num)
Tusimple 数据的标注特点:
1、车道线实际上不只是道路上的标线,虚线被当作了一种实线做处理的。这里面双实线、白线、黄线这类信息也是没有被标注的。
2、每条线实际上是点序列的坐标集合,而不是区域集合