3. 数据基础
Occupancy网络训练的第一步不是搭模型,而是把“三维空间被占据的情况”变成网络能读、能学、能评估的数据。与检测框、语义分割掩码不同,Occupancy标签描述的是体素级或查询点级的空间占据状态,它同时携带几何、语义与可见性信息。理解数据格式、标注规范和主流数据集,是后续训练与部署工程能否复现、能否迁移的前提。
一、Occupancy数据的核心表示
当前工业界与学术界常见的Occupancy表示可归为三类:稠密体素栅格、稀疏体素/点查询以及隐式场查询。稠密体素把空间切成规则网格,每个体素存占据概率或语义类别,结构规整、便于3D卷积,但显存随分辨率立方增长;稀疏体素只保留被占据或靠近表面的体素,配合稀疏卷积可显著降低计算量;隐式场则把Occupancy建模为连续函数,训练时在空间采样查询点,输出该点的占据与语义,适合高分辨率与任意查询位置。
无论哪种表示,一条Occupancy样本通常包含以下字段:自车坐标系下的空间范围(如x∈[-40,40]m、y∈[-40,40]m、z∈[-5,3]m)、体素分辨率(如0.4m或0.2m)、每个体素的占据状态(free/occupied/unknown)、语义类别(如车辆、行人、可行驶区域、路沿、植被、建筑等),以及可见性掩码。可见性掩码用于区分“真实为空”和“未被观测到”,这是Occupancy标注与普通3D检测标签最大的差异之一。
关键点:Occupancy标签不是“看到什么标什么”,而是“在给定传感器视野与遮挡关系下,推断每个空间单元是否被占据”。因此unknown区域必须显式建模,否则网络会把未观测区域误学成free。
二、标注规范与生成流程
Occupancy标注成本极高,纯人工逐体素标注几乎不可行。主流方案是“多传感器融合自动生成 + 人工校验/补标”。典型流程如下:
- 多帧点云聚合:将激光雷达多帧点云配准到同一自车坐标系,形成稠密点云,作为几何证据。
- 图像语义投影:用2D语义分割结果反投影到3D空间,为点云或体素提供语义先验。
- 表面重建与体素化:对点云做泊松重建或TSDF融合,得到表面,再按分辨率体素化,标记occupied/free。
- 可见性计算:从传感器原点做射线投射,标记被遮挡或超出量程的体素为unknown。
- 人工校验:在可视化工具中检查漏标、错标,重点修正动态物体、细长结构(如杆、行人)和地面边界。
标注规范中需要特别约定:动态物体是否按当前帧位置标注;地面与可行驶区域是否单独成类;远处稀疏区域是否降级为unknown;以及类别体系是否与下游规划控制对齐。这些约定直接决定网络输出能否被部署端消费。
工程建议:在项目早期就固定一套“类别ID + 颜色映射 + 分辨率 + 空间范围”的元数据文件(如JSON/YAML),训练、可视化、评估、部署共用同一份,避免格式漂移。
三、常见数据集:nuScenes与Waymo
目前公开的Occupancy相关数据主要来自两大自动驾驶数据集及其衍生标注。
| 数据集 | 传感器配置 | Occupancy相关标注 | 典型用途 |
|---|---|---|---|
| nuScenes | 6相机 + 1激光雷达 + 5毫米波雷达 | 官方提供3D检测与分割;社区衍生Occ3D-nuScenes提供体素级占据与语义标签 | 多模态Occupancy预训练、时序融合 |
| Waymo Open Dataset | 5相机 + 多激光雷达 | 3D检测与跟踪;Waymo Occupancy Flow提供体素占据与运动流 | 高精度几何、占据流预测 |
| SemanticKITTI | 单激光雷达 | 逐点语义标注,可体素化生成Occupancy | 激光雷达语义分割基线 |
| Occ3D / OpenOccupancy | 基于nuScenes/Waymo衍生 | 统一体素级占据+语义+可见性 | Occupancy预测基准评测 |
nuScenes的优势在于多模态同步与场景多样性,适合验证相机为主的Occupancy方案;Waymo的激光雷达点云更密,几何精度更高,适合研究高分辨率占据与占据流。实际工程中,常先用nuScenes做快速迭代,再用自采数据做域适配。
四、数据读取与格式示例
以体素级Occupancy为例,常见存储为压缩的numpy数组或稀疏索引。下面是一个简化的读取与解析示例:
import numpy as np
# occ: [X, Y, Z] uint8, 0=free, 1=occupied, 255=unknown
# sem: [X, Y, Z] uint8, 语义类别ID
occ = np.load("sample_occ.npz")["occupancy"]
sem = np.load("sample_occ.npz")["semantics"]
# 空间范围与分辨率
pc_range = [-40, -40, -5, 40, 40, 3] # [x_min,y_min,z_min,x_max,y_max,z_max]
voxel_size = 0.4 # 米
# 将体素索引转换为自车坐标
def voxel_to_point(ix, iy, iz):
x = pc_range[0] + (ix + 0.5) * voxel_size
y = pc_range[1] + (iy + 0.5) * voxel_size
z = pc_range[2] + (iz + 0.5) * voxel_size
return x, y, z
occupied_idx = np.argwhere(occ == 1)
print("occupied voxels:", occupied_idx.shape[0])
训练时通常还会构造可见性掩码,只对可见区域计算损失,unknown区域忽略。评估指标常用IoU、mIoU以及针对occupied类的精度/召回。
五、常见误区与复盘
- 把unknown当free:导致网络在遮挡区域“幻觉”出可行驶空间,部署时风险极高。
- 分辨率与感受野不匹配:0.2m分辨率下,40m×40m×8m需要约1.28亿体素,必须用稀疏表示或分块训练。
- 类别体系与下游不一致:训练时细分“卡车/挂车”,部署端只关心“是否可通行”,会造成标签浪费与映射错误。
- 忽略时序一致性:Occupancy是连续空间状态,单帧标注抖动会让网络学到噪声,建议多帧聚合与平滑。
- 直接跨数据集混训:nuScenes与Waymo的坐标系、类别、分辨率不同,需先统一到同一元数据规范。
复盘结论:Occupancy数据工程的核心是“元数据统一 + 可见性建模 + 类别对齐”。数据格式一旦确定,训练、评估、部署都应围绕同一份规范展开,任何环节私自修改分辨率或类别ID,都会导致模型无法复现或部署失败。
综上,Occupancy数据基础可以概括为:用统一的元数据规范描述空间范围、分辨率、占据状态、语义与可见性;用多传感器融合加人工校验生成标签;用nuScenes、Waymo等公开数据集快速起步,再通过自采数据完成域适配。只有把数据格式与标注规范固定下来,后续的网络训练与部署工程才有稳定的输入基础。