一文搞懂Nuscenes数据集
一. Nuscenes数据集简介先来简单的介绍一下Nuscenes数据集相信大家对Nuscenes数据集应该是有一些了解的至少应该知道这是和自动驾驶相关的知道这些就足够了下面再来补充一些知识Nuscenes数据的采集来自不同城市的1000个场景中采集车上配备了完善的传感器包括6个相机CAM、1个激光雷达LIDAR、5个毫米波雷达RADAR、IMU和GPS。传感器在采集车上的布置如下图所示可以看出相机CAM有六个分别分布在前方Front、右前方Front Right、左前方Front Left、后方Back、右后方Back Right、左后方Back Left激光雷达LIDAR有1个放置在车顶TOP毫米波雷达有五个分别放置在前方Front、右前方Front Right、左前方Front Left、右后方Back Right、左后方Back Left。二. 准备工作✨✨✨数据才是王道第一步我们当然是需要下载数据了。Nuscenes的官网下载链接如下https://www.nuscenes.org/download。第一次下载应该是需要进行登录的登录完成就可以进行下载啦登录完成你可能会发现有太多可下载的资源了我该下载哪一个呢这里我们用做实验故不需要下载完整的数据集下载mini版本即可【完整的太大了mini大约4个G】。下载完成进行解压后应该有如下的文件结构接下来我们对上图中的4个文件进行分析maps文件夹可以看到maps文件夹中是4个地图的图片这种图片信息的文件我们很容易理解这里不过多叙述。samples文件夹samples文件夹存放的是上文提到的传感器6个相机、1个激光雷达、5个毫米波雷达所采集到的信息。不信你可以打开6个相机所对应的文件夹你可以发现里面都是采集到的图片至于激光雷达和毫米波雷达所对应的文件夹里也存储着各自采集的信息只是格式不能像图片那样直接进行查看。sweeps文件夹sweeps文件夹其结构和samples文件夹是完全一样的。那么samples文件夹和sweeps文件夹有什么区别呢可以这样理解samples文件夹中存储的信息是较为关键、重要的而sweeps文件夹中的信息则相对次要。v1.0-mini文件夹这里存的是json文件这些json文件可以分为4个部分车辆信息(Vehicle)、数据提取(Extraction)、注释(Annotation)、分类信息Taxonomy。这些文件都有对应的关系后边会详细解释下每个文件中存的是什么内容具体的对应关系如下图所示下面将从数据读取的方式对每个json文件进行详细的解释1. 安装库首先需要按照nuscenes-devkit库使用pip安装即可。pip install nuscenes-devkit2. 导入相关模块和数据集from nuscenes.nuscenes import NuScenes nusc NuScenes(versionv1.0-mini, datarootE:\\毫米波雷达\\v1.0-mini, verboseTrue) print(nusc)上图红框中的内容不知大家是否有种似曾相似的感觉没错就是之前v1.0-mini文件夹中的那些文件。3. 日志 log记录每个数据采集的元数据。logfile: 日志文件名。vehicle: 参与采集的车辆名称。date_captured: 数据采集日期。location: 数据采集地点例如新加坡。map_token: 外键对应map地图中的token。print(nusc.log[0])输出结果4. 地图 map存储地图信息。tokens: 一个日志外键列表指向log表中与该地图相关的日志记录。category: 地图类别目前仅支持语义先验semantic_prior用于可驾驶区域和人行道。filename: 存储地图数据的文件名log_tokens: 这是一个列表用来存放与该地图相关的所有log_token。这意味着同一张地图可以被多次数据采集任务复用print(nusc.map[0])输出结果可以看出来map.json中的token和log.json中的map_token是对齐的。5. 场景scene⭐⭐⭐scene 表示一个20s长的帧序列。name: 场景名称。description: 场景的详细描述。log_token: 外键指向log表中的一条记录。nbr_samples: 场景中的样本数。first_sample_token: 外键指向场景中的第一个样本。last_sample_token: 外键指向场景中的最后一个样本。map和scene都指向log,因为都包含一个log_token,这是因为日志会每个场景都提供基础数据而每个地图也会对应一个日志文件不过不是直接通过外键实现。print(nusc.list_scenes())输出结果: mini数据集中只包含10个场景每个场景大约持续20s【有的19s】即每个场景有20秒采集到的信息。可以使用下列命令来查看某个场景中的信息my_scene nusc.scene[0] print(my_scene)输出结果token为唯一标识通过token可以获取对应信息。6. 样本sample⭐⭐⭐先来说说sample和scene的关系前面说到每个scene大约持续20s那sample就是每0.5秒进行一次采样。也可以这样理解sample和scenesence相当于20s的视频sample就是每0.5s取一帧的图像。timestamp: 时间戳。scene_token: 外键指向scene表表示样本属于哪个场景。next: 下一个样本的外键指向时间序列中的下一个样本。prev: 上一个样本的外键指向时间序列中的上一个样本。data:传感器数据索引键是传感器通道名值是sample_data的token。标注索引包含该帧中所有 3D 标注框的token列表。sample与scene 之间每个场景包含多个样本一场景多样本一样本对应一场景所以二者之间双箭头类似于数学中的某个映射关系。上文已经得到了某个场景的信息【scene-0061】现可以通过my_scene得到某一个sample的token值。first_sample_token my_scene[first_sample_token] #获取第一个sample的token值 print(first_sample_token)输出结果当我们得到第一个sample的token值后我们可以通过nusc.get命令来获取当前sample的信息my_sample nusc.get(sample, first_sample_token) print(my_sample)输出结果结果中包含了传感器采集到的信息、标注信息等等。7. 样本数据 sample_data⭐⭐⭐sample_data 存储了传感器的数据包括图像、点云、雷达返回值等。sample_token: 外键指向sample表表示该数据属于哪个样本。ego_pose_token: 外键指向车辆的姿态信息ego_pose表。calibrated_sensor_token: 外键指向calibrated_sensor表表示该数据来自哪个校准的传感器。timestamp微秒级时间戳。fileformat:文件格式如 pcd、jpg、png等。is_key_frame: 是否为关键帧。filename: 存储传感器数据的文件名。width和height: 图像数据则表示图像的宽度和高度。prev指向上一个sample_data的外键。next指向下一个sample_data的外键。print(my_sample[data])输出结果这些传感器里包含了许多的样本数据我们可以使用下列命令来将这些传感器中采集的进行可视化sensor_radar RADAR_FRONT #这里选择的传感器为前方的毫米波雷达传感器 radar_front_data nusc.get(sample_data,my_sample[data][sensor_radar]) print(radar_front_data)输出结果nusc.render_sample_data(radar_front_data[token])这里只展示了RADAR_FRONT即前方毫米波雷达传感器的可视化结果可视化其他传感器的方法和上文一致。8. 车辆姿态 ego_poseego_pose 存储车辆在采集数据时的位置信息包括在全局坐标系中的位置和方向。token车辆唯一标识符。translation: 车辆的三维位置单位为米。rotation: 车辆的四元数旋转表示车辆的方向。timestamp: 采集数据的时间戳。print(nusc.ego_pose[0])输出结果9. 校准传感器 calibrated_sensorcalibrated_sensor 存储特定传感器在车辆上的校准参数。sensor_token: 外键指向sensor表表示传感器类型。translation: 传感器的三维位置单位为米。rotation: 传感器的四元数旋转表示其在车辆上的方向。camera_intrinsic: 摄像头的内参矩阵如果是非摄像头传感器则为空。token唯一标识符。sensor_token nusc.calibrated_sensor[0] print(sensor_token)输出结果可以看出token字段对应的值和sample_data中calibrated_sensor_token的值是一致的。sample_data与ego_pose:每个样本数据都依赖车辆的姿态信息记录数据采集时车辆的位置和方向sample_data与calibrated_sensor:传感器数据依赖于校准的传感器样本数据记录了采集时的传感器状态。10. 传感器 sensorsensor 存储传感器的基本信息如类型和通道名称。channel: 传感器通道名称例如CAM_FRONT表示前方摄像头。modality: 传感器类型例如摄像头camera、激光雷达lidar或雷达radar。token: 唯一标识符。calibrated_sensor 与 sensor 这个很好理解每个校准传感器需要知道类型表明是哪种传感器。print(nusc.sensor)输出结果可以看出RADAR_FRONT中的token和上述 calibrated_sensor中sensor_token字段的结果一致。因sample_data中就存储着传感器的信息因此可以通过nusc.sample_data[i]来获取传感器的信息结果如下print(nusc.sample_data[0])输出结果11. 实例 instanceinstance 存储每个物体的实例。例如每个车辆、行人等都是一个物体实例。category_token: 外键指向category表表示物体的类别。nbr_annotations: 该实例的注释数量。first_annotation_token和last_annotation_token: 外键分别指向该实例的第一个和最后一个注释。token:唯一标识符。my_instance nusc.instance[0] print(my_instance)输出结果我们也可以可视化这个实例instance_token my_instance[token] nusc.render_instance(instance_token)输出结果12. 类别categorycategory 定义了物体的分类例如车辆或行人。name: 类别名称例如vehicle.car。description: 类别的描述。index: 用于快速查找类别的索引。category 和 instance : 每个物体实例都属于一个类别。print(nusc.list_categories())输出结果nusc.category[i]表示获取第i个类别的信息print(nusc.category[0])13. 样本标注 sample_annotation⭐⭐⭐sample_annotation 定义了样本中物体的位置和形状。所有位置数据都是相对于全局坐标系。token:主键标注的唯一标识符。sample_token:外键指向sample.json,表示关键帧。instance_token: 外键指向instance表表示物体的实例。attribute_tokens: 外键列表表示该注释的属性例如物体是移动还是静止。visibility_token: 外键表示物体的可见性。translation: 物体的中心坐标。size: 物体的尺寸宽、长、高。rotation: 物体的四元数旋转表示物体的方向。prev:外键指向同一实例的上一帧标注 token。next:外键指向同一实例的下一帧标注 token。num_lidar_pts:该标注框内包含的激光雷达点云数量。num_radar_pts:该标注框内包含的毫米波雷达点云数量。上文提到my_sample中包含了传感器采集到的信息、标注信息在sample_data中已经展示了传感器采集到的信息这一部分将展示样本标注的信息方法与之前是类似的。my_annotation_token my_sample[anns][18] my_annotation_metadata nusc.get(sample_annotation,my_annotation_token) print(my_annotation_metadata)输出结果可视化nusc.render_annotation(my_annotation_metadata[token])14. 属性attributeattribute 存储了物体的一些动态属性例如车辆是停着的还是行驶中的。name: 属性名称例如vehicle.moving。description: 属性的详细描述。token:主键标注的唯一标识符。print(nusc.list_attributes())输出结果属性在一个场景中是可以变换的下列代码展示了行人从移动到站立属性发生了变换。【注意这部分代码直接看可能不是很好理解将代码一部分一部分的运行看看每步的结果你就会恍然大悟】my_instance nusc.instance[27] first_token my_instance[first_annotation_token] last_token my_instance[last_annotation_token] nbr_samples my_instance[nbr_annotations] current_token first_token i 0 found_change False while current_token ! last_token: current_ann nusc.get(sample_annotation, current_token) current_attr nusc.get(attribute, current_ann[attribute_tokens][0])[name] if i 0: pass elif current_attr ! last_attr: print(Changed from {} to {} at timestamp {} out of {} annotated timestamps.format(last_attr, current_attr, i, nbr_samples)) found_change True next_token current_ann[next] current_token next_token last_attr current_attr i 1输出结果15. 可见性visibilityvisibility 定义了物体在所有图像中的可见性划分为四个等级0-40%40-60%60-80%80-100%。level: 可见性等级。description: 可见性等级的描述。token:主键标注的唯一标识符。anntoken my_sample[anns][9] visibility_token nusc.get(sample_annotation, anntoken)[visibility_token] print(Visibility: {}.format(nusc.get(visibility, visibility_token))) nusc.render_annotation(anntoken)输出结果sample_annotation与sample:每个样本都有多个注释信息注释包括了物体在场景中的位置和属性sample_annotation与instance每个注释都对应一个物体实例反之每个物体实例可以有多个注释sample_annotation与attribute属性与样本注释关联用于描述物体在注释时的状态。sample_annotation与visibility每个注释都记录了物体的可见性这些可见性信息与样本注释关联。注外键一种数据库的约束用来确保表中的一列或多列引用另一张表中的主键外键用于建立两个表之间的关联全局坐标系是一个参考框架用于在特定空间内表示物体的位置和方向。与车辆本地坐标系基于车辆自身的参考系不同全局坐标系是所有物体的统一参考系。校准参数将传感器如摄像头、激光雷达、雷达等相对于车辆的位置、方向进行准确描述的参数。这些参数包括传感器的位置信息位置和旋转和内部参数如摄像头的内参矩阵图中的回旋箭头时间序列上前后关联形成闭环 sample中的前一个样本可以指向下一个样本下一个样本可以指向前一个样本形成了一个时间序列上的循环关系。这是我在通过SUSTechPOINTS标注工具默认生成的标注json转成成nuscenes数据集总结的如果大家也在用SUSTechPOINTS标注工具进行标注对转成nuscenes数据集一头雾水可以找我要相关代码。