感知栈的形态由承载它的车辆所决定。将同一套软件移植到新的车系——例如,从SUV换到轿车或产品组合中的其他车型变体——其对世界的感知就会发生变化。传感器布局、标定、视场、遮挡、车身几何、时序和覆盖范围都会改变。交通灯可能出现在画面中的不同位置。路缘可能变得更难看清。覆盖边缘附近的行人可能变得难以判断。当自动驾驶栈扩展到新的车系和变体时,即使底层感知栈保持不变,开发人员也必须考虑这些差异。
为每个车系收集和标注新的真实世界数据集成本高昂,而且在车辆开发早期可能无法实现。新车辆可能尚未到位,罕见场景也并非总能被捕获。真实驾驶数据对于系统性能的落地和验证仍然至关重要,但合成数据可以帮助团队在完整的目标车系数据集存在之前就适配模型。
车系适配的挑战在于,为一辆可能尚不存在的车辆准备感知软件,并将该软件扩展到多个平台变体,而无需为每个变体收集和标注大型数据集。
NVIDIA Omniverse NuRec 让这一过程更加可行。它从记录的真实驾驶数据出发,重建每个场景,并为目标车辆配置渲染新的相机视图。
开发人员可以复用真实世界数据来回答以下问题:
- 从目标传感器配置来看,这个场景会是什么样子?
- 哪些现有驾驶数据能很好地覆盖新车辆?
- 几何变化在哪些地方造成了薄弱点?
- 哪些缺口需要真实采集?
本文展示如何利用现有驾驶数据,通过以下四个步骤将感知栈适配到新的传感器配置:
- 将重建的驾驶数据与目标传感器配置配对。
- 渲染目标视图。
- 使用 NVIDIA Harmonizer 优化帧。
- 在输出上训练感知模型。
本教程使用来自 NVIDIA Physical AI NuRec Dataset to complete 的重建场景来完成这四个步骤。
NuRec 如何支持车系适配
NuRec 使用 3D 高斯泼溅从传感器数据重建真实世界环境,并将其渲染用于仿真。对于车系适配,NuRec 重建由现有车辆捕获的真实驾驶数据,并从目标车辆的视角渲染新的相机流。
NuRec 的两项能力对车系适配特别有用。
新视角合成:NuRec 可以使用 gsplat 渲染场景,通过指定的相机模型投影高斯。这一能力使用户能够更改相机外参、内参、视场和镜头模型,包括针孔、鱼眼和 f-theta 配置。可复用的场景数据和标注:重建的场景保留了原始传感器配置轨迹、逐相机标定、动态物体轨迹和地图数据。这些资产可用于在新渲染的视图中对齐或适配物体、车道、交通灯和道路边界等标注。

图 1. NuRec 车系适配工作流。重建的 USDZ 场景通过目标车系的传感器配置进行渲染,使用 Harmonizer 进行优化,并用于感知训练
使用 NuRec 将感知模型适配到新车系
以下工作流展示了开发团队如何通过目标相机配置渲染已有的重建行驶数据、优化生成的帧,并为感知模型训练准备数据。
步骤 1. 下载重建场景
Hugging Face 上的 Physical AI NuRec 数据集包含超过 1,500 个神经重建驾驶场景。每个场景时长约 20 秒,由六个相机视角重建而成:一个 120 度前广角视角、一个 30 度前长焦视角、120 度左交叉和右交叉视角,以及 70 度左后和右后视角。
NuRec 数据集设有访问限制。接受许可协议,使用 Hugging Face token 进行身份验证,然后下载一个场景。
import os
from huggingface_hub import login, snapshot_download
login(token=os.getenv("HF_TOKEN"))
# Download one reconstructed scene (USDZ) from the 26.04 release
snapshot_download(
repo_id="nvidia/PhysicalAI-Autonomous-Vehicles-NuRec",
repo_type="dataset",
allow_patterns="sample_set/26.04_release/<scene-uuid>/*",
)
如果使用编码代理,请克隆 NVIDIA/nurec-skills 仓库。它包含用于下载 Physical AI 数据集、使用 NuRec 进行渲染以及优化输出帧的技能。
git clone https://github.com/NVIDIA/nurec-skills.git
步骤 2. 从目标车系的传感器装置进行渲染

图 2. 同一 NuRec 重建场景分别从原始相机装置和偏移后的目标相机装置渲染的结果
本教程使用公共示例中附带的一个合成目标相机装置。其相机名称、位姿、分辨率和镜头参数均为示例性内容。
所提供的合成装置包含一个目标相机,因此本教程生成一路目标相机流。在装置文件中,每个传感器条目定义一个以冒号分隔的相机名称、图像分辨率、F-Theta 镜头模型、内参以及相机到装置的位姿。
NRE 将以冒号分隔的名称转换为逻辑相机 ID。例如,它将 camera:front:synthetic:120fov 转换为 camera_front_synthetic_120fov。要添加另一个目标相机,请向 rig.sensors 添加另一个条目。为其指定唯一名称,并提供其自身的宽度、高度、镜头模型、内参以及 nominalSensor2Rig_FLU 变换。
设置输入和输出位置:
export SCENE_DIR=/absolute/path/to/scene
export SCENE_FILE=<SCENE_UUID>.usdz
export RIG_DIR=/absolute/path/to/rig
export RIG_FILE=minimal-synthetic-target-rig.json
export OUTPUT_DIR=/absolute/path/to/output
mkdir -p "$OUTPUT_DIR"
将公共 NuRec 容器固定到其不可变摘要,并拉取镜像:
export NUREC_IMAGE='nvcr.io/nvidia/nre/nre-ga:26.04.01@sha256:97f43e7130c5636ce3e80ea3184d97f56a87fdd989b05cce42230881dbdea284'
docker pull "$NUREC_IMAGE"
docker image inspect "$NUREC_IMAGE" --format '{{range .RepoDigests}}{{println .}}{{end}}'
将轨迹导出和渲染作为独立的容器操作运行。导出目标相机轨迹:
docker run --rm --gpus all --shm-size=64g \
-v "$SCENE_DIR":/inputs/scene:ro \
-v "$RIG_DIR":/inputs/rig:ro \
-v "$OUTPUT_DIR":/outputs \
"$NUREC_IMAGE" export-custom-rig-trajectory \
--artifact-path="/inputs/scene/$SCENE_FILE" \
--rig-json="/inputs/rig/$RIG_FILE" \
--output=/outputs/custom_rig_trajectories.json
接下来,运行一个目标相机的稀疏渲染以验证设置。在此示例中,选择目标相机 camera_front_synthetic_120fov,因为示例目标 rig 定义了一个前向相机。渲染命令加载导出的轨迹文件,然后使用 –camera-id 选择要渲染的相机。
USDZ 场景是使用六个源相机重建的:一个 120 度前向广角相机、一个 30 度前向长焦相机、120 度交叉左和交叉右相机,以及 70 度后左和后右相机。目标相机不需要与这些源相机一一对应。它可以使用不同的位置、朝向、分辨率、视场角或标定,只要其位姿在同一 rig 坐标系中表达,并且其镜头模型受导出器支持即可。放置在观测轨迹之外较远位置或朝向源相机覆盖有限区域的相机可能会产生质量较低的渲染。
本教程使用一个前向目标相机,要适配其他视角,例如后左相机,首先向目标 rig JSON 添加一个后左传感器,为其提供后左相机到 rig 的外参,再次导出轨迹,并将其规范化逻辑 ID 传递给 –camera-id。
docker run --rm --gpus all --shm-size=64g \
-v "$SCENE_DIR":/inputs/scene:ro \
-v "$OUTPUT_DIR":/outputs \
"$NUREC_IMAGE" render \
--artifact-path="/inputs/scene/$SCENE_FILE" \
--output-dir=/outputs/smoke \
--custom-rig-trajectory=/outputs/custom_rig_trajectories.json \
--no-replicate-training-views \
--renderer=default \
--image-format=png \
--frame-step=30 \
--image-scale=1 \
--frame-naming=frame-end-timestamp \
--camera-id=camera_front_synthetic_120fov
检查这些帧,确保姿态、视场角和时间戳正确。在稀疏渲染通过审核后,使用 –frame-step=1 为所有目标相机渲染完整序列。对目标 rig 中每个已验证的相机重复使用 –camera-id。
第 3 步:优化渲染帧
神经渲染可能会留下依赖视角的伪影、不一致的颜色或色调,以及重建效果不佳的动态物体。NVIDIA Harmonizer 是一个公开的、具有时间感知能力的后处理模型,可修正 NuRec 及相关神经渲染中的伪影。它能提升视觉质量,但无法修复错误的标定、恢复从未被重建的场景覆盖范围,也无法替代目标相机验证。
NVIDIA/nurec-skills 中的 nurec-fixer 技能涵盖了设置、推理、评估以及可选的 Harmonizer 微调。首先,在下载模型之前验证主机。
git clone https://github.com/NVIDIA/nurec-skills.git
python nurec-skills/skills/nurec-fixer/scripts/validate_setup.py
在 Hugging Face 上接受模型许可,克隆 Harmonizer 仓库,构建其运行时镜像,并下载已发布的检查点:
git clone https://github.com/NVIDIA/harmonizer.git
cd harmonizer
docker build -t harmonizer-cosmos-env -f Dockerfile.cosmos .
hf auth login
./download_checkpoints.sh
test -f models/diffusion_harmonizer.pkl
test -d src/checkpoints/nvidia/Cosmos-Predict2-0.6B-Text2Image
一次运行一个相机序列。挂载父渲染目录,以便输出——写入输入目录旁边——在主机上持久保存:
export HARMONIZER_DIR=/absolute/path/to/harmonizer
export RENDER_ROOT=/absolute/path/to/output/render
export CAMERA_ID=camera_front_synthetic_120fov
docker run --rm --gpus all --ipc=host \
--entrypoint python \
-v "$HARMONIZER_DIR":/work \
-v "$RENDER_ROOT":/frames \
-w /work/src \
harmonizer-cosmos-env \
inference_pix2pix_turbo_harmonizer.py \
--input_image="/frames/$CAMERA_ID" \
--model_path=/work/models/diffusion_harmonizer.pkl \
--model_identifier=harmonized \
--timestep=250 \
--resolution=1024 \
--use_sched

图 3. 原始 NuRec 渲染与 NVIDIA Harmonizer 输出的并排对比。Harmonizer 减少了可见的天空伪影并提升了视觉一致性(右侧)
步骤 4. 训练感知模型
在为新的车型系列创建 NuRec 渲染数据集后,在将其纳入感知训练流程之前,先验证输出结果。像对待从车辆采集的真实相机数据一样对待这个新数据集。然后,根据感知模型的需求准备使用它。
车型系列适配项目
NVIDIA 在一个需要支持新相机配置的内部自动驾驶项目中评估了此工作流。团队拥有来自另一辆车的现有驾驶数据库,但目标车型系列的数据尚不可用。

图 4. 在为目标车型系列使用 NuRec 渲染的合成数据训练后,与零样本基线相比,目标检测精确率和召回率的相对提升。VRU 指弱势道路使用者
使用 NuRec 智能体技能自动化工作流
NVIDIA/nurec-skills 仓库将主要步骤打包为智能体技能。编码智能体可以使用 physical-ai-datasets 来定位和下载场景,使用 nre 来渲染它们,并使用 nurec-fixer 来优化输出。
如需端到端示例,请观看神经重建智能体技能直播。
视频 1. 了解 NVIDIA Omniverse NuRec 如何使用 3D 高斯泼溅重建真实世界驾驶场景,并为自动驾驶车辆仿真进行渲染
公开的 NVIDIA/nurec-skills 仓库包含用于定位 Physical AI 数据集、使用 NCore、运行 NuRec 以及应用 DiffusionHarmonizer 的技能。nurec-carline-adaptation
技能添加了一个轻量级的兼容性和来源层;它不会重新分发 NuRec 源代码或模型。
git clone https://github.com/NVIDIA/nurec-skills.git
克隆仓库后,向兼容的编码代理发出以下指令:
使用 $nurec-carline-adaptation 技能验证此 USDZ 和经过清理的目标绑定,向我展示确切的本地 Docker 命令,运行一次稀疏的单摄像头冒烟测试,并在任何摄像头或挡风玻璃检查失败时,在完整渲染之前停止。
将 NuRec 应用于现有驾驶数据
重建一次采集的驾驶过程,需要来自录制设备的同步视频以及同一次录制的相应元数据。然后,必须将源数据组织成一致的布局:
clip/
└── raw/
├── generated/
│ ├── front_wide.mp4
│ ├── front_tele.mp4
│ ├── cross_left.mp4
│ ├── cross_right.mp4
│ ├── rear_left.mp4
│ ├── rear_right.mp4
│ └── rear.mp4
└── clipgt/parquets/
├── calibration_estimate.parquet
├── egomotion_estimate.parquet
└── object_fused.parquet
MP4 来自车辆的摄像头录像机。Parquet 文件包含完整摄像头装置共享的元数据。
| 输入 | 包含内容 | 典型来源 |
|---|---|---|
calibration_estimate.parquet |
摄像头镜头参数和安装位置 | 摄像头标定或装置配置导出 |
egomotion_estimate.parquet |
车辆随时间的位置和姿态 | 定位、里程计、VIO 或 SLAM |
object_fused.parquet |
移动物体、类别、尺寸和轨迹 ID | 感知或标注流水线 |
*表 1.*所需元数据文件、其内容和典型来源本教程中使用的配套转换器和重建配方需要全部三个 Parquet 文件。其他 NuRec 工作流可能支持无需物体轨迹的重建。这些文件名和 Parquet 序列化并非 NCore 要求。如果相同信息存储在 JSON、数据库或其他格式中,可以调整公开的 NCore 转换器模板以读取源数据。
此工作流假设所选视频已同步且覆盖相同的录制区间。标定数据必须标识每个所选摄像头,自运动数据必须覆盖从首次曝光到末次曝光的整个序列,并且此配方所需的物体轨迹必须与该区间重叠并使用相同的世界坐标系。语义验证器在转换后运行,并在生成的 NCore 序列中检查这些关系。
将源数据映射到 NCore
下一节中的配套转换器支持上文所示的七视频和三表布局。当文件遵循此模式时,工作流可以直接继续执行 运行配套转换器。
不支持的源格式需要定制公开转换器模板的副本,以读取源文件并将数据写入 NCore。
export CONVERTER_DIR="$WORK_DIR/cosmos-clipgt-converter"
cp -R "$NUREC_SKILLS_REPO/skills/ncore/ncore_template" "$CONVERTER_DIR"
该模板是一个代码骨架,而非通用转换器。其源数据读取器必须将等价信息映射到以下 NCore 组件中:
| 源数据 | NCore V4 |
|---|---|
| 编码相机图像与逐帧曝光区间 | 每个逻辑相机对应一个 CameraSensorComponent |
| 相机镜头模型与内参 | IntrinsicsComponent |
| 相机到 rig 的外参 | PosesComponent : T_sensor_rig |
| 度量自运动 | PosesComponent : T_rig_world |
| 可选的全局参考 | PosesComponent : T_world_world_global |
| 自车掩码 | MasksComponent |
| 物体观测与轨迹 | CuboidsComponent |
表 2. 源数据到 NCore V4 组件的映射遵循公开的 NCore 坐标约定:
- Rig:
+X
向前,+Y
向左,+Z
向上 - 相机:
+X
向右,+Y
向下,+Z
向前 - 时间戳:整数微秒
- 距离:米;位姿:有效的 SE(3) 变换
将位姿计算保持在 float64 中。重设局部 world 帧的基准,使第一个 rig 位姿为单位矩阵。对于没有记录帧时间戳的同步恒定帧率视频,帧 i 的标称时间戳为:
frame_timestamp_us = anchor_timestamp_us + i * 1,000,000 / fps
在可用时使用记录的曝光时间戳。标称公式假设 MP4 流已同步。转换器使用 NCore separate-sensors 配置文件写入序列。此配置文件为每个转换后的相机创建一个相机组件归档,并为位姿、内参、掩码和长方体创建一个共享归档。转换器保留每个相机的实际分辨率和颜色解释。
运行配套转换器
当源特定转换器随教程仓库一起分发时,按如下方式运行:
export COSMOS_CONVERTER="$TUTORIAL_REPO/tools/cosmos_ncore/build_cosmos_ncore_v4.py"
test -f "$COSMOS_CONVERTER"
env -u PYTHONPATH "$NCORE_PYTHON" "$COSMOS_CONVERTER" \
--root "$INPUT_ROOT" \
--anchor-us "$ANCHOR_TIMESTAMP_US" \
--sequence-id "$SEQUENCE_ID" \
--fps "$FPS" \
--store-type itar
验证 NCore 序列
根据转换器的输出约定设置生成的路径:
export NCORE_DIR="$INPUT_ROOT/ncore/$SEQUENCE_ID"
export NCORE_MANIFEST="$NCORE_DIR/$SEQUENCE_ID.json"
export NCORE_VALIDATOR="$TUTORIAL_REPO/tools/cosmos_ncore/validate_cosmos_ncore_v4.py"
test -s "$NCORE_MANIFEST"
python3 -m json.tool "$NCORE_MANIFEST" > /dev/null
运行特定于源的验证器:
env -u PYTHONPATH "$NCORE_PYTHON" "$NCORE_VALIDATOR" \
--root "$INPUT_ROOT" \
--sequence-id "$SEQUENCE_ID"
然后使用公共 NCore 查看器检查序列,并打开 http://localhost:8080。
export NCORE_REPO=/absolute/path/to/ncore
export NCORE_MANIFEST=/absolute/path/to/sequence/<sequence-id>.json
(
cd "$NCORE_REPO"
bazel run //tools/ncore_vis -- \
v4 \
--component-group="$NCORE_MANIFEST"
)
预期输出
一个分离传感器的 NCore V4 序列通常包含:
<sequence-id>/
├── <sequence-id>.json
├── build_manifest.json
├── <sequence-id>.ncore4.zarr.itar
├── <sequence-id>.ncore4-<camera-id>.zarr.itar
└── ... 每个已转换相机对应一个相机归档文件
共享的 <sequence-id>.ncore4.zarr.itar 归档包含姿态、内参、掩码和长方体等组件。每个 <sequence-id>.ncore4-<camera-id>.zarr.itar 归档包含一个已转换相机的帧。JSON 清单和所有引用的归档构成一个逻辑序列;它们必须保持在一起。
生成 NuRec 辅助数据
转换后的 NCore 序列包含记录的传感器测量值、标定、姿态和对象轨迹。它尚未包含此仅相机重建工作流所需的推断语义分割、深度和自我掩码。公开的 skills/nre 说明描述了此阶段,而 NuRec 辅助数据文档 定义了数据产品。NGC 上的公开 nre-tools-ga NGC 容器 提供了推理应用程序。
该工作流使用 NRE_AUX_IMAGE
来识别辅助数据容器,并将其与单独的 nre-ga
训练和渲染镜像区分开。26.04 GA 镜像通过一个入口点暴露多个工具,因此工作流显式选择 ncore-aux-data 子命令:
export NUREC_AUX_IMAGE=nvcr.io/nvidia/nre/nre-tools-ga:26.04.00
python3 "$NUREC_SKILLS_REPO/skills/nre/scripts/validate_setup.py" --strict
docker pull "$NUREC_AUX_IMAGE"
docker run --rm --gpus all --shm-size=2g \
--env NGC_API_KEY \
--volume "$NCORE_DIR:/workdir/dataset" \
"$NUREC_AUX_IMAGE" ncore-aux-data \
--dataset-path="/workdir/dataset/$SEQUENCE_ID.json" \
--output-dir=/workdir/dataset \
--segmentation-backend=mask2former \
--depth-backend=depthanythingv2 \
--max-depth-m=80 \
--ego-mask \
--no-lidar-seg-camvis \
--no-seg-logits \
--zarr-store-type=itar \
--store-meta \
--num-threads=auto
所选选项具有明确的角色。表 3 总结了每个所选选项生成的输出。
| 选项 | 生成的产品 |
|---|---|
--segmentation-backend=mask2former |
<sequence-id>.aux.sseg.zarr.itar:逐帧语义类别掩码 |
--depth-backend=depthanythingv2 |
<sequence-id>.aux.depth.zarr.itar:度量深度 |
--ego-mask |
<sequence-id>.aux.egomask.zarr.itar:逐相机自车排除掩码 |
--store-meta |
<sequence-id>.aux-meta.json:来自固定镜像的已解析辅助设置 |
--no-lidar-seg-camvis |
禁用 LiDAR 分割,因为该工作流不包含 LiDAR 数据 |
*表 3.*辅助数据选项与生成的产品省略 --camera-id
会处理 NCORE_SEQUENCE_JSON 中声明的每个相机。选择特定相机需要为每个相机提供一个`
--camera-id=<logical-camera-id>
参数,使用清单中的逻辑相机 ID。
辅助数据生成后,重建输入目录包含以下结构:
<sequence-id>/
├── <sequence-id>.json
├── build_manifest.json
├── <sequence-id>.ncore4.zarr.itar
├── <sequence-id>.ncore4-<camera-id>.zarr.itar
└── ... one camera archive per converted camera
├── <sequence-id>.aux.sseg.zarr.itar
├── <sequence-id>.aux.depth.zarr.itar
├── <sequence-id>.aux.egomask.zarr.itar
└── <sequence-id>.aux-meta.json
开始使用
使用以下资源,开始将重建的场景适配到目标车型。
- 从Physical AI NuRec 数据集下载 USDZ 场景及其中包含的示例目标装配。 - 通过示例装配渲染该场景,将装配 JSON 替换为目标车型配置,然后再次渲染该场景。
- 查阅NuRec 文档,了解安装要求、支持的硬件、验证及渲染说明。 - 如需重建录制的行驶数据,请遵循
重建 AV 场景以及NVIDIA/nurec-skills中的 NCore 转换与辅助数据指南。 - 使用
NVIDIA Harmonizer进行时间一致的序列后处理。
公开的软件、容器、数据集和模型产物需要相应的 NVIDIA NGC 或 Hugging Face 账户,并接受其许可协议。NuRec 运行时可在 NGC 上的 nre-ga 容器中获取。
