从Waymo到nuScenes:手把手教你用Python玩转两大自动驾驶数据集的可视化与格式转换
2026/5/25 3:41:05 网站建设 项目流程

Waymo与nuScenes数据集实战指南:Python可视化与格式转换全解析

自动驾驶算法的快速发展离不开高质量数据集的支撑。作为行业两大标杆,Waymo和nuScenes数据集各有特色,但它们的格式差异常常让研究者头疼。本文将带你深入理解这两个数据集的核心特点,并手把手教你用Python实现数据可视化与格式转换的完整流程。

1. 两大数据集核心对比

Waymo和nuScenes虽然都是自动驾驶领域的重量级数据集,但在数据组织、传感器配置和标注方式上存在显著差异。理解这些差异是高效使用它们的前提。

1.1 传感器配置对比

特性Waymo Open DatasetnuScenes
激光雷达5个(顶部1个,四周4个)1个32线激光雷达
摄像头5个(前、左前、右前、左、右)6个(覆盖360°视野)
雷达5个毫米波雷达
数据采集频率10Hz2Hz(关键帧)
数据格式TFRecordJSON+二进制文件

Waymo的传感器配置更密集,特别是激光雷达系统提供了更全面的环境感知能力。而nuScenes的毫米波雷达数据为研究多传感器融合提供了独特资源。

1.2 标注内容差异

Waymo标注特点:

  • 包含车辆、行人、骑行者等对象的3D边界框
  • 提供对象跟踪ID,支持时序分析
  • 每个对象有运动状态标签(如静止、移动)
  • 场景级天气和光照条件标注

nuScenes标注亮点:

  • 更细粒度的对象分类(23个类别)
  • 属性标注(如车辆是否停放、行人是否携带物品)
  • 场景描述和语义地图
  • 每个对象有可见性评分
# Waymo标签解析示例 import waymo_open_dataset.protos.label_pb2 as label_pb2 def parse_waymo_label(label): type_map = { label_pb2.Label.TYPE_VEHICLE: "vehicle", label_pb2.Label.TYPE_PEDESTRIAN: "pedestrian", label_pb2.Label.TYPE_CYCLIST: "cyclist" } return type_map.get(label.type, "unknown")

2. 环境配置与数据准备

2.1 安装必要依赖

处理这两个数据集需要不同的Python库支持。建议使用conda创建独立环境:

# 创建conda环境 conda create -n ad_dataset python=3.8 conda activate ad_dataset # 安装Waymo相关依赖 pip install waymo-open-dataset-tf-2-12-0==1.6.4 # 安装nuScenes相关依赖 pip install nuscenes-devkit matplotlib==3.3.4

注意:Waymo数据集库对TensorFlow版本有严格要求,建议使用TF 2.12.0以避免兼容性问题。

2.2 数据目录结构

合理的目录结构能显著提高工作效率:

datasets/ ├── waymo/ │ ├── raw/ # 原始TFRecord文件 │ ├── processed/ # 处理后的中间文件 │ └── visuals/ # 可视化结果 └── nuscenes/ ├── v1.0-mini/ # 迷你版数据集 ├── maps/ # 地图数据 └── exports/ # 转换输出

3. 数据可视化实战

3.1 Waymo点云与图像同步可视化

Waymo数据的三维点云与多视角图像精确同步,这是其独特优势。以下代码展示如何实现同步可视化:

import matplotlib.pyplot as plt from waymo_open_dataset import dataset_pb2 from waymo_open_dataset.utils import frame_utils def visualize_waymo_frame(frame): # 解析激光雷达数据 lidar_data = frame_utils.parse_range_image_and_camera_projection(frame) points = lidar_data[0] # 顶部激光雷达点云 # 解析相机图像 images = [] for image in frame.images: images.append(tf.image.decode_jpeg(image.image)) # 创建可视化布局 fig = plt.figure(figsize=(24, 12)) # 显示点云 ax1 = fig.add_subplot(121, projection='3d') ax1.scatter(points[:, 0], points[:, 1], points[:, 2], s=0.1) # 显示前视相机图像 ax2 = fig.add_subplot(122) ax2.imshow(images[0]) plt.tight_layout() plt.show()

3.2 nuScenes三维标注可视化

nuScenes提供了丰富的场景上下文信息,以下代码展示如何可视化带语义标注的场景:

from nuscenes.utils.data_classes import LidarPointCloud from nuscenes.utils.geometry_utils import view_points def visualize_nuscenes_sample(nusc, sample_token): sample = nusc.get('sample', sample_token) # 获取点云数据 lidar_data = nusc.get('sample_data', sample['data']['LIDAR_TOP']) pcl_path = os.path.join(nusc.dataroot, lidar_data['filename']) pc = LidarPointCloud.from_file(pcl_path) # 获取标注信息 annotations = [nusc.get('sample_annotation', token) for token in sample['anns']] # 可视化 fig = plt.figure(figsize=(12, 12)) ax = fig.add_subplot(111, projection='3d') # 绘制点云 points = view_points(pc.points[:3, :], np.eye(4), normalize=False) ax.scatter(points[0, :], points[1, :], points[2, :], s=0.1) # 绘制标注框 for ann in annotations: box = nusc.get_box(ann['token']) box.render(ax, view=np.eye(4)) plt.show()

4. 格式转换高级技巧

4.1 Waymo转COCO格式

将Waymo转换为通用的COCO格式可以方便地使用大量现有视觉算法。以下是关键转换步骤:

  1. 提取图像和标注:从TFRecord中解码JPEG图像和对应的2D/3D标注
  2. 坐标系转换:将Waymo坐标系转换为COCO的标准格式
  3. 类别映射:统一对象类别定义
  4. 生成JSON文件:构建符合COCO规范的标注文件
import json from waymo_open_dataset import label_pb2 def waymo_to_coco(tfrecord_path, output_dir): dataset = tf.data.TFRecordDataset(tfrecord_path, compression_type='') coco_data = { "images": [], "annotations": [], "categories": [ {"id": 1, "name": "vehicle"}, {"id": 2, "name": "pedestrian"}, {"id": 3, "name": "cyclist"} ] } ann_id = 1 for frame_id, data in enumerate(dataset): frame = dataset_pb2.Frame() frame.ParseFromString(bytearray(data.numpy())) # 处理图像 for cam_id, image in enumerate(frame.images): img_info = { "id": f"{frame_id}_{cam_id}", "file_name": f"frame_{frame_id}_cam_{cam_id}.jpg", "width": image.image.shape[1], "height": image.image.shape[0] } coco_data["images"].append(img_info) # 处理该图像对应的标注 for label in frame.projected_lidar_labels[cam_id].labels: ann = { "id": ann_id, "image_id": img_info["id"], "category_id": label.type, "bbox": [label.box.center_x, label.box.center_y, label.box.length, label.box.width], "area": label.box.length * label.box.width } coco_data["annotations"].append(ann) ann_id += 1 # 保存COCO格式标注 with open(os.path.join(output_dir, 'annotations.json'), 'w') as f: json.dump(coco_data, f)

4.2 nuScenes转KITTI格式

KITTI格式广泛用于点云目标检测,转换nuScenes数据可扩展其应用场景:

def nuscenes_to_kitti(nusc, sample_token, output_dir): sample = nusc.get('sample', sample_token) # 获取点云数据 lidar_data = nusc.get('sample_data', sample['data']['LIDAR_TOP']) pcl_path = os.path.join(nusc.dataroot, lidar_data['filename']) # 创建KITTI格式目录 os.makedirs(os.path.join(output_dir, 'velodyne'), exist_ok=True) os.makedirs(os.path.join(output_dir, 'label_2'), exist_ok=True) # 转换点云 pc = LidarPointCloud.from_file(pcl_path) points = pc.points[:3, :].T points = np.c_[points, np.zeros(len(points))] # 添加反射率维度 points.astype(np.float32).tofile( os.path.join(output_dir, 'velodyne', f'{sample_token}.bin')) # 转换标注 with open(os.path.join(output_dir, 'label_2', f'{sample_token}.txt'), 'w') as f: for ann_token in sample['anns']: ann = nusc.get('sample_annotation', ann_token) box = nusc.get_box(ann_token) # KITTI格式:类别 truncated occluded alpha bbox2d bbox3d dimensions location rotation_y line = f"{ann['category_name']} 0 0 0 " line += f"{box.orientation.yaw} " line += f"{box.wlh[0]} {box.wlh[1]} {box.wlh[2]} " line += f"{box.center[0]} {box.center[1]} {box.center[2]}\n" f.write(line)

5. 高效处理大规模数据的技巧

处理自动驾驶数据集常面临数据量大的挑战。以下是几个提升效率的实用技巧:

5.1 并行处理TFRecord文件

Waymo数据集通常由多个TFRecord文件组成,使用并行处理可显著加速:

import multiprocessing def process_waymo_file(file_path): # 处理单个文件的代码 pass def parallel_process_waymo(input_dir, output_dir): files = [f for f in os.listdir(input_dir) if f.endswith('.tfrecord')] with multiprocessing.Pool(processes=4) as pool: pool.starmap(process_waymo_file, [(os.path.join(input_dir, f), output_dir) for f in files])

5.2 使用内存映射加速nuScenes访问

对于频繁访问的nuScenes数据,使用内存映射可以减少IO开销:

def load_nuscenes_with_mmap(nusc, sample_token): sample = nusc.get('sample', sample_token) lidar_data = nusc.get('sample_data', sample['data']['LIDAR_TOP']) # 使用numpy内存映射加载点云 pcl_path = os.path.join(nusc.dataroot, lidar_data['filename']) points = np.memmap(pcl_path, dtype=np.float32, mode='r', shape=(lidar_data['num_points'], 5)) return points

5.3 数据采样策略

对于开发调试,使用数据子集能大大提高效率:

Waymo数据采样建议:

  • 按时间间隔采样(如每10帧取1帧)
  • 按场景类型筛选(如只选择白天场景)
  • 使用官方提供的验证集小样本

nuScenes数据采样技巧:

  • 使用官方v1.0-mini版本
  • 按场景token哈希值采样
  • 根据标注数量筛选样本
# nuScenes场景采样示例 def sample_nuscenes_scenes(nusc, sample_ratio=0.1): all_scenes = nusc.scene sampled_scenes = [] for scene in all_scenes: if hash(scene['token']) % 100 < sample_ratio * 100: sampled_scenes.append(scene) return sampled_scenes

6. 实战案例:跨数据集模型验证

为了展示两大数据集的实用价值,我们设计一个跨数据集验证实验:

  1. 在Waymo上训练:使用其丰富的3D标注训练检测模型
  2. 在nuScenes上测试:评估模型泛化能力
  3. 结果分析:比较不同传感器配置下的性能差异

关键实现步骤:

  • 统一两个数据集的类别定义
  • 处理不同的坐标系和单位
  • 适配不同的评估指标
def cross_dataset_evaluation(waymo_model, nusc_dataset): results = [] for scene in nusc_dataset.scene: first_sample_token = scene['first_sample_token'] sample = nusc_dataset.get('sample', first_sample_token) # 获取点云 lidar_data = nusc_dataset.get('sample_data', sample['data']['LIDAR_TOP']) points = LidarPointCloud.from_file( os.path.join(nusc_dataset.dataroot, lidar_data['filename'])) # 转换到Waymo坐标系 points = transform_to_waymo_coords(points) # 使用Waymo模型推理 detections = waymo_model.predict(points.points[:3, :].T) # 转换回nuScenes坐标系 detections = transform_to_nuscenes_coords(detections) # 评估 metrics = evaluate_on_nuscenes(nusc_dataset, sample, detections) results.append(metrics) return aggregate_results(results)

提示:跨数据集验证时,特别注意两个数据集的标注标准差异,如行人的最小高度阈值可能不同,这会影响性能比较的公平性。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询