深入nuScenes数据集(3/6)
in Tutorial with 0 comment
深入nuScenes数据集(3/6)
in Tutorial with 0 comment

这是一篇跟着官方教程走的深入文章,官方教程有6篇。现在这篇是 nuimages_tutorial.ipynb,也就是第三篇,链接:here

6篇教程分别如下:

背景

在nuImages中,使用2D边界框、实例掩码和2D分割掩码对物体进行注释。所有来自nuScenes的标签和属性都被保留在nuImages中。我们还在nuImages中添加了更多属性。对于分割,我们包括了"stuff"(背景)类别。

数据集被构建为一个带有表格、令牌和外键的关系数据库。以下是这些表格:

2023-05-26T10:52:25.png

准备工作

下载数据集:需要先注册,邮箱注册即可,然后进入下载页:https://www.nuscenes.org/download,找到 nuImages mini,md5: a64f0ae03ffab9d943254f9cedf93b26,点击 Asia,即可下载,因为是官方是使用了 aws s3 进行存储,如果遇到下载不畅,请自备魔法。

将下载好的数据集解压到~/data_sets,完整的目录是/Users/lau/data_sets/nuimages,这个目录后面会用到。

目录结构如下:

tree -L 2
.
├── samples
│   ├── CAM_BACK
│   ├── CAM_BACK_LEFT
│   ├── CAM_BACK_RIGHT
│   ├── CAM_FRONT
│   ├── CAM_FRONT_LEFT
│   └── CAM_FRONT_RIGHT
├── sweeps
│   ├── CAM_BACK
│   ├── CAM_BACK_LEFT
│   ├── CAM_BACK_RIGHT
│   ├── CAM_FRONT
│   ├── CAM_FRONT_LEFT
│   └── CAM_FRONT_RIGHT
└── v1.0-mini
    ├── attribute.json
    ├── calibrated_sensor.json
    ├── category.json
    ├── ego_pose.json
    ├── log.json
    ├── object_ann.json
    ├── sample.json
    ├── sample_data.json
    ├── sensor.json
    └── surface_ann.json

阅读数据集

启动 jupyter,创建nuImages.ipynb

pip install nuscenes-devkit
%matplotlib inline
%load_ext autoreload
%autoreload 2
from nuimages import NuImages

nuim = NuImages(dataroot='/Users/lau/data_sets/nuimages', version='v1.0-mini', verbose=True, lazy=True)

# 输出结果
======
Loading nuImages tables for version v1.0-mini...
Done loading in 0.000 seconds (lazy=True).
======

如上所述,NuImages类包含多个表格。每个表格都是记录列表,每个记录都是一个字典。例如,category表的第一条记录存储在:

nuim.category[0]

# 输出结果
Loaded 25 category(s) in 0.001s,
{'token': '63a94dfa99bb47529567cd90d3b58384',
 'name': 'animal',
 'description': 'All animals, e.g. cats, rats, dogs, deer, birds.'}
nuim.table_names

# 输出结果
['attribute',
 'calibrated_sensor',
 'category',
 'ego_pose',
 'log',
 'object_ann',
 'sample',
 'sample_data',
 'sensor',
 'surface_ann']

Indexing

由于所有的表格都是字典列表,我们可以使用标准的Python操作来处理它们。一个非常常见的操作是通过令牌来检索特定的记录。由于这个操作的时间复杂度是线性的,我们预先计算了一个索引,以便能够在常数时间内访问记录。

让我们选择这个数据集版本中的第一张图像并进行切分:

sample_idx = 0
sample = nuim.sample[sample_idx]
sample

# 输出结果
Loaded 50 sample(s) in 0.001s,
{'token': '09acd654cb514bdeab8e3afedad74fca',
 'timestamp': 1535352274870176,
 'log_token': '4ed5d1230fcb48d39db895f754e724f9',
 'key_camera_token': '0128b121887b4d0d86b8b1a43ac001e9'}

我们也可以通过token获取样本记录

sample = nuim.get('sample', sample['token'])
sample

# 输出结果
{'token': '09acd654cb514bdeab8e3afedad74fca',
 'timestamp': 1535352274870176,
 'log_token': '4ed5d1230fcb48d39db895f754e724f9',
 'key_camera_token': '0128b121887b4d0d86b8b1a43ac001e9'}

这实际上是在查找索引。我们可以看到这与我们最初使用的索引是相同的。

sample_idx_check = nuim.getind('sample', sample['token'])
assert sample_idx == sample_idx_check

通过样本,我们可以直接访问相应的关键帧样本数据。这在下面的操作中会很有用。

key_camera_token = sample['key_camera_token']
print(key_camera_token)

# 输出结果
0128b121887b4d0d86b8b1a43ac001e9

Lazy loading

上面初始化NuImages实例非常快,因为我们实际上没有加载表格。相反,该类实现了延迟加载,通过覆盖内部的__getattr__()函数,在内存中没有存储表格时加载表格。当我们访问category时,我们可以看到表格从磁盘中加载。如果要禁用此类通知,请在初始化NuImages对象时设置verbose=False。此外,可以通过lazy=False禁用延迟加载。

渲染

要渲染一张图像,我们使用render_image()函数。我们可以看到每个对象类别的边界框和掩码,以及自车和可行驶表面的表面掩码。我们使用以下颜色:

在每个框的左上角,我们可以看到对象类别的名称(如果with_category=True)。我们还可以设置with_attributes=True来显示每个对象的属性(请注意,只有在with_category=True时,我们才可以设置with_attributes=True来显示每个对象的属性)。此外,我们可以通过将with_annotations设置为all、surfaces、objectsnone来指定是否要看到表面和对象,或仅看到表面,或仅看到对象,或都不看。

通过设置render_scale=2,我们可以使图像更大以提高可见性。我们还可以使用box_line_width来更改边界框的线宽。通过将其设置为-1,线宽将根据render_scale进行自适应。最后,我们可以使用out_path将图像渲染到磁盘中。

nuim.render_image(key_camera_token, annotation_type='all',
                  with_category=True, with_attributes=True, box_line_width=-1, render_scale=5)

# 输出结果
Loaded 650 sample_data(s) in 0.005s,
Loaded 58 surface_ann(s) in 0.002s,
Loaded 506 object_ann(s) in 0.003s,
Loaded 12 attribute(s) in 0.001s,

2023-05-26T12:17:20.png

object_tokens, surface_tokens = nuim.list_anns(sample['token'])

# 输出结果
Printing object annotations:
06eed0ca8b164b84bbb2851de1ed2c13 vehicle.car ['vehicle.moving']
0e8ba57c7b69482c88319f5c1b4deeb0 movable_object.trafficcone []
11ec9a46540443339e2e38afbe31f7b1 human.pedestrian.adult ['pedestrian.standing']
4b27e4a70d464cb2a2f33d5dbcf85094 human.pedestrian.adult ['pedestrian.moving']
4c76bc9ee7da40668f1d4b294209ae3b human.pedestrian.adult ['pedestrian.standing']
4e61ccd6905644adb0556e1f336cee79 movable_object.barrier []
584cb4bd0e7c4a0b8b1169191ca828a1 vehicle.car ['vehicle.moving']
677a87b7df1a4ee7a7a36bab569cccbd human.pedestrian.adult ['pedestrian.moving']
683e330396134c6393fd77187194990c human.pedestrian.adult ['pedestrian.moving']
82e0c68c0f2440bcb041a51a6f116513 human.pedestrian.adult ['pedestrian.moving']
8dc2b24b1a69434a8aade0cb4e308e8e vehicle.car ['vehicle.moving']
924572ff00404ae59d1ee2f6f6c92274 human.pedestrian.adult ['pedestrian.moving']
9b8ea679730b43d7b6631ceeb56e0ccf human.pedestrian.adult ['pedestrian.moving']
a457fc08800444bc83900e3a12b00619 movable_object.barrier []
c4308276d2ab463b9aca936c4c5d1dfb vehicle.bus.rigid ['vehicle.moving']
d287a7310b0a44cda3aa75215cdb676a human.pedestrian.adult ['pedestrian.moving']

Printing surface annotations:
f573eaa17a595521a39c4116f05a6f58 flat.driveable_surface

我们可以看到对象注释(object_ann)和表面注释(surface_ann)的令牌。让我们再次渲染图像,但只关注第一个对象和第一个表面注释。我们可以使用如下所示的object_tokens和surface_tokens参数。我们可以看到只有一辆车和可行驶表面被渲染出来。

nuim.render_image(key_camera_token, with_category=True, object_tokens=[object_tokens[0]], surface_tokens=[surface_tokens[0]])

2023-05-26T12:18:51.png

要获取上述内容的原始数据(即分割掩码,包括语义和实例分割),我们可以使用get_segmentation()函数。

import matplotlib.pyplot as plt

semantic_mask, instance_mask = nuim.get_segmentation(key_camera_token)

plt.figure(figsize=(32, 9))

plt.subplot(1, 2, 1)
plt.imshow(semantic_mask)
plt.subplot(1, 2, 2)
plt.imshow(instance_mask)

plt.show()

2023-05-26T12:19:44.png

每个标注的图像(关键帧)都带有最多6个过去的图像和6个未来的图像,时间间隔为500毫秒+-250毫秒。然而,只有少部分样本具有较少的sample_data,这可能是因为它们位于日志的开头或结尾,或者由于延迟或丢失的数据包。list_sample_content()函数显示每个样本的所有相关sample_data。

nuim.list_sample_content(sample['token'])

# 输出结果
Listing sample content...
Rel. time    Sample_data token
     -3.0    0b4fd0e270f2421fbdb7c27caadbc593
     -2.5    f3eadc785a024b3b8af093927d476c2a
     -2.0    aa7dee3a4b824f8a9d894398f18ba1c4
     -1.5    051086dc1e8243fab8731ef5ad7e90a8
     -1.0    26ce6186cc71496fbe07b0b1988c6fb5
     -0.5    24614975bbb34bf385559d958df8008b
      0.0    0128b121887b4d0d86b8b1a43ac001e9
      0.5    5bdc01f564a14f0196817df2a53a41da
      1.0    0a6a50a883f842cba3bf758925b391c6
      1.5    be49e96e81ec4314a6db1f73112ae08f
      2.0    8a18bc3e590b4e0ba904ada6259d1122
      2.5    f1d8370634a948f78084681c25eb9fd6
      3.0    c079819d1520412eb8b99b1c485b1718

除了已注释的图像外,我们还可以渲染6个先前的图像和6个未来的图像,它们没有被注释。让我们选择下一张图像,它是在注释图像之后约0.5秒拍摄的。我们可以手动从上面的列表中复制令牌,或者使用sample_data的next指针。

next_camera_token = nuim.get('sample_data', key_camera_token)['next']
next_camera_token

# 输出结果
'5bdc01f564a14f0196817df2a53a41da'
try:
    nuim.render_image(next_camera_token, annotation_type='none')
except Exception as e:
    print('As expected, we encountered this error:', e)

2023-05-26T12:22:31.png

官方还提供了一个名为render_images.py的脚本,就在here,它可以在nuImages的随机子集上运行这些渲染函数中的一个或全部。要运行它,只需在命令行中执行以下命令。这将把前置摄像头的图像、深度图、点云和轨迹渲染保存到指定的文件夹中。

>> python nuimages/scripts/render_images.py --mode all --cam_name CAM_FRONT --out_dir ~/Downloads/nuImages --out_type image

不仅可以渲染注释的关键帧,还可以渲染以2 Hz间隔的13个单独图像的视频。

>> python nuimages/scripts/render_images.py --mode all --cam_name CAM_FRONT --out_dir ~/Downloads/nuImages --out_type video

车辆姿态和CAN数据

ego_pose提供了与每个sample_data最接近的平移、旋转、旋转速率、加速度和速度测量值。我们可以在每个注释的关键帧的6秒剪辑中可视化自车的轨迹。在这里,红色的x表示轨迹的起点,绿色的o表示注释关键帧的位置。我们可以设置rotation_yaw,使得注释关键帧时的行驶方向在图中指向"上方"。我们也可以将rotation_yaw设置为None,以使用默认方向(指向北方)。要获取此图的原始数据,请使用get_ego_pose_data()get_trajectory()

nuim.render_trajectory(sample['token'], rotation_yaw=0, center_key_pose=True)

2023-05-26T12:27:10.png

统计

list_*()方法对于获取数据集维度的概览非常有用。请注意,这些统计数据始终针对我们使用NuImages实例初始化的当前拆分,而不是整个数据集。

nuim.list_logs()

# 输出结果
Loaded 44 log(s) in 0.001s,

Samples Log                           Location                
     1 n003-2018-01-03-12-03-23+0800 singapore-onenorth      
     1 n003-2018-01-04-11-23-25+0800 singapore-onenorth      
     1 n003-2018-01-08-11-30-34+0800 singapore-onenorth      
     1 n003-2018-07-12-15-40-35+0800 singapore-onenorth      
     1 n004-2018-01-04-11-05-42+0800 singapore-onenorth      
     2 n005-2018-06-14-20-11-03+0800 singapore-onenorth      
     1 n006-2018-09-17-12-15-45-0400 boston-seaport          
     1 n008-2018-03-14-15-16-29-0400 boston-seaport          
     3 n008-2018-05-21-11-06-59-0400 boston-seaport          
     1 n008-2018-05-30-15-20-59-0400 boston-seaport          
     2 n008-2018-05-30-16-31-36-0400 boston-seaport          
     1 n008-2018-06-04-16-30-00-0400 boston-seaport          
     1 n008-2018-09-18-14-18-33-0400 boston-seaport          
     1 n009-2018-05-08-15-52-41-0400 boston-seaport          
     1 n009-2018-09-12-09-59-51-0400 boston-seaport          
     1 n010-2018-07-05-14-36-33+0800 singapore-onenorth      
     1 n010-2018-07-06-11-01-46+0800 singapore-onenorth      
     1 n010-2018-08-27-12-00-23+0800 singapore-onenorth      
     1 n010-2018-08-27-15-10-53+0800 singapore-onenorth      
     1 n010-2018-09-17-15-57-10+0800 singapore-onenorth      
     1 n013-2018-08-01-16-46-39+0800 singapore-onenorth      
     1 n013-2018-08-02-13-54-05+0800 singapore-onenorth      
     1 n013-2018-08-02-14-08-14+0800 singapore-onenorth      
     1 n013-2018-08-03-14-44-49+0800 singapore-onenorth      
     2 n013-2018-08-16-16-15-38+0800 singapore-onenorth      
     2 n013-2018-08-20-14-38-24+0800 singapore-onenorth      
     1 n013-2018-08-21-11-46-25+0800 singapore-onenorth      
     1 n013-2018-08-27-11-35-10+0800 singapore-onenorth      
     1 n013-2018-08-27-14-41-26+0800 singapore-onenorth      
     1 n013-2018-08-27-15-47-08+0800 singapore-onenorth      
     1 n013-2018-08-27-16-40-42+0800 singapore-onenorth      
     1 n013-2018-08-28-16-04-27+0800 singapore-onenorth      
     1 n013-2018-08-29-11-41-15+0800 singapore-onenorth      
     1 n013-2018-08-29-14-19-16+0800 singapore-onenorth      
     1 n013-2018-09-03-14-54-42+0800 singapore-onenorth      
     1 n013-2018-09-04-13-30-50+0800 singapore-onenorth      
     1 n014-2018-06-25-21-03-46-0400 boston-seaport          
     1 n015-2018-09-05-12-12-46+0800 singapore-onenorth      
     1 n015-2018-09-13-15-25-57+0800 singapore-onenorth      
     1 n015-2018-09-19-11-19-35+0800 singapore-onenorth      
     1 n016-2018-07-04-10-44-39+0800 singapore-onenorth      
     1 n016-2018-07-06-12-06-18+0800 singapore-queenstown    
     1 n016-2018-07-10-11-22-35+0800 singapore-onenorth      
     1 n016-2018-07-10-16-55-57+0800 singapore-onenorth  

list_categories()会列出类别的频率,以及类别的名称和描述。每个类别要么是对象,要么是表面,而不会同时存在。

nuim.list_categories(sort_by='object_freq')

# 输出结果

Object_anns Surface_anns Name                     Description                                     
        189            0 human.pedestrian.adult   Adult subcategory.                              
        122            0 vehicle.car              Vehicle designed primarily for personal use, e.g
         70            0 movable_object.barrier   Temporary road barrier placed in the scene in or
         44            0 movable_object.trafficco All types of traffic cone.                      
         28            0 vehicle.truck            Vehicles primarily designed to haul cargo includ
         14            0 vehicle.bicycle          Human or electric powered 2-wheeled vehicle desi
         14            0 vehicle.motorcycle       Gasoline or electric powered 2-wheeled vehicle d
          6            0 human.pedestrian.constru Construction worker                             
          5            0 vehicle.bus.rigid        Rigid bus subcategory.                          
          5            0 vehicle.construction     Vehicles primarily designed for construction. Ty
          3            0 human.pedestrian.persona A small electric or self-propelled vehicle, e.g.
          2            0 movable_object.pushable_ Objects that a pedestrian may push or pull. For 
          2            0 vehicle.trailer          Any vehicle trailer, both for trucks, cars and b
          1            0 movable_object.debris    Movable object that is left on the driveable sur
          1            0 static_object.bicycle_ra Area or device intended to park or secure the bi
          0           49 flat.driveable_surface   Surfaces should be regarded with no concern of t
          0            9 vehicle.ego              Ego vehicle.     

我们还可以在list_categories()中指定sample_tokens参数,以获取特定一组样本的类别统计信息。

sample_tokens = [nuim.sample[9]['token']]
nuim.list_categories(sample_tokens=sample_tokens)

# 输出结果
Object_anns Surface_anns Name                     Description                                     
          3            0 movable_object.barrier   Temporary road barrier placed in the scene in or
          1            0 human.pedestrian.constru Construction worker                             
          1            0 vehicle.car              Vehicle designed primarily for personal use, e.g
          1            0 vehicle.construction     Vehicles primarily designed for construction. Ty
          1            0 vehicle.truck            Vehicles primarily designed to haul cargo includ
          0            1 flat.driveable_surface   Surfaces should be regarded with no concern of t

list_attributes()显示所有属性的频率、名称和描述:

nuim.list_attributes(sort_by='freq')

# 输出结果

Annotations Name                     Description                                     
        100 pedestrian.moving        The human is moving.                            
         81 vehicle.parked           Vehicle is stationary (usually for longer durati
         66 vehicle.moving           Vehicle is moving.                              
         54 pedestrian.standing      The human is standing.                          
         41 pedestrian.sitting_lying The human is sitting or lying down.             
         24 cycle.without_rider      There is NO rider on the bicycle or motorcycle. 
         15 vehicle.stopped          Vehicle, with a driver/rider in/on it, is curren
          7 cycle.with_rider         There is a rider on the bicycle or motorcycle.  
          0 vehicle_light.emergency. Vehicle is flashing emergency lights.           
          0 vehicle_light.emergency. Vehicle is not flashing emergency lights.       
          0 vertical_position.off_gr Object is not on the ground plane, e.g. flying, 
          0 vertical_position.on_gro Object is on the ground plane.     

list_cameras()会显示每个通道(如前置摄像头)的摄像头条目和样本数量。每个摄像头使用略有不同的内部参数,这些参数将在未来的发布中提供。

nuim.list_cameras()

# 输出结果
Loaded 50 calibrated_sensor(s) in 0.004s,
Loaded 6 sensor(s) in 0.002s,

Calibr. sensors Samples Channel                  
              5       5 CAM_FRONT_LEFT           
              9       9 CAM_BACK_RIGHT           
              7       7 CAM_FRONT_RIGHT          
             10      10 CAM_BACK_LEFT            
              8       8 CAM_FRONT                
             11      11 CAM_BACK                 

list_sample_data_histogram()显示了每个带有注释的关键帧中图像数量的直方图。请注意,每个关键帧最多有13个图像。对于此处显示的迷你分割,所有关键帧都有13个图像。

nuim.list_sample_data_histogram()

# 输出结果
Listing sample_data frequencies..
# images    # samples
      13    50

参考

Responses