模拟/建模/设计

借助 NVIDIA Omniverse NuRec 在车辆平台上扩展智能汽车感知

感知堆栈由搭载该堆栈的车辆决定形状。将相同的软件移动到新的赛车系 (例如,从 SUV 到轿车或产品组合中的其他车型) ,它对世界的感知会发生变化。传感器的位置、校准、视野、遮挡、人体几何图形、定时和覆盖度都会发生变化。红绿灯可能会出现在画面的不同部分。路边的路况会变得越来越难看。靠近覆盖范围边缘的行人可能会变得模糊不清。随着自动驾驶堆栈扩展到新的车型和变体,即使底层感知堆栈保持不变,开发者也必须考虑到这些差异。

为每辆赛车收集和标记新的现实世界数据集的成本很高,而且在车辆开发初期可能不可能实现。新车队可能不可用,并且无法始终捕获罕见情况。真实的驾驶数据对于确定和验证系统性能仍然至关重要,但合成数据可以帮助团队在完整的目标轴向数据集出现之前调整模型。

Carline 适应性挑战是为可能尚不存在的车辆准备感知软件,并跨平台变体扩展该软件,而无需为每个变体收集和标记大型数据集。

NVIDIA Omniverse NuRec 使这个过程更加实用。它从录制的真实驾驶开始,重建每个场景,并渲染目标车辆配置的新摄像头视图。

开发者可以重复使用真实数据来提出以下问题:

  1. 从目标装备来看,这个场景会是什么样子?
  2. 现有的哪些驱动能够很好地覆盖新车?
  3. 几何图形的变化在哪里会造成薄弱点?
  4. 哪些差距需要实际收集?

本文介绍了如何通过以下四个步骤,使用现有的驱动数据使感知堆栈适应新的传感器装备:

  1. 将重建的驾驶与目标装备配置配对。
  2. 渲染目标视图。
  3. 使用 NVIDIA Harmonizer 优化帧。
  4. 在输出上训练感知模型。

本教程使用 NVIDIA 物理 AI NuRec 数据集中的重建场景来完成四个步骤。

NuRec 如何支持 carline 适应性

NuRec 使用 3D Gaussian splatting 根据传感器数据重建现实环境,并对其进行渲染以进行仿真。为了适应轮轴,NuRec 可重建现有车辆捕获的真实驾驶,并从目标车辆的视角渲染新的摄像头流。

两个 NuRec 功能对于 carline 适应性特别有用。

  • 新视角合成: NuRec 可以使用 gsplat 渲染场景,gsplat 通过指定的摄像头模型投射高斯图。此功能使用户能够更改相机外部构造、内部构造、视野和镜头模型,包括针孔、鱼眼和 f-theta 配置。
  • 可重复使用的场景数据和注释:重建后的场景保留了原始装备轨迹、每个摄像头的校正、动态物体追踪和地图数据。这些素材可用于对齐或调整新渲染视图中的标签,例如物体、车道、交通信号灯和道路边界。

使用 NuRec 使感知模型适应新的车道

以下工作流程展示了开发团队如何通过目标摄像头设备渲染现有的重建驾驶、优化生成的帧,以及准备用于感知模型训练的数据。

第 1 步:。下载重建的场景

Hugging Face 上的物理 AI NuRec 数据集包含 1500 多个神经重建的驾驶场景。每个场景的时长约为 20 秒,由六个摄像头视角重建而成:120 度正视角、30 度正视角、120 度左右交叉视角,以及 70 度左右后视角。

NuRec 数据集已设置门控。接受许可,使用 Hugging Face 令牌进行身份验证,然后下载一个场景。

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 存储库。其中包括下载物理 AI 数据集、使用 NuRec 进行渲染以及优化输出帧的技能。

git clone https://github.com/NVIDIA/nurec-skills.git

第 2 步:。从目标线条的传感器设备进行渲染

本教程使用公开示例中包含的合成目标摄像头装备。其摄像头名称、姿态、分辨率和镜头参数均可供参考。

所提供的合成设备包含一个目标摄像头,因此本教程会生成一个目标摄像头流。在装备文件中,每个传感器条目都定义了冒号分隔的相机名称、图像分辨率、F-Theta 镜头模型、内部参数以及从相机到装备的姿态。

NRE 将冒号分隔的名称转换为逻辑摄像头 ID。例如,它将 camera:Front:synthetic:120fov 转换为 camera_front_synthetic_120fov。要添加另一个目标摄像头,请在 rig.sensors 中添加另一个条目。为其指定唯一名称,并提供其自身的宽度、高度、镜头模型、内部参数和 nimalSensor2Rig_FLU transform。

设置输入和输出位置:

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,因为示例目标装备定义了前置摄像头。渲染命令加载导出的轨迹文件,然后使用 – camera-id 选择要渲染的摄像头。

USDZ 场景由六个源摄像头重建而成:一个 120 度 正面摄像头、一个 30 度 正面长焦摄像头、120 度 左右交叉摄像头以及 70 度 左右前后摄像头。目标摄像头不需要与任何这些源摄像头进行一对一对应。它可以使用不同的位置、方向、分辨率、视野或校准,前提是其姿态在同一装备坐标系中表示,并且其镜头模型得到导出工具的支持。放置在观测轨迹之外的摄像头或瞄准源摄像头覆盖范围有限的区域的摄像头可能会产生低质量的渲染。

本教程使用前置目标摄像头来调整另一个视图 (例如左后摄像头) ,首先在目标设备 JSON 中添加左后传感器,为其提供从后置到左侧的摄像头外部元素,再次导出轨迹,然后将其标准化逻辑 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` 渲染所有目标摄像头的完整序列。为目标设备中每个经过验证的摄像头重复执行 – 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

第 4 步:。训练感知模型

在为新汽车线条创建 NuRec 渲染的数据集后,请先验证输出,然后再将其整合到感知训练工作流中。以类似于从车辆中收集的真实摄像头数据的方式处理此新数据集。然后,根据感知模型的需求准备使用。

Carline 适应计划

NVIDIA 在内部自动驾驶程序中评估了这一工作流程,该程序需要支持新的摄像头配置。该团队拥有一个来自不同车辆的现有驾驶库,但尚未提供目标车道数据。

借助 NuRec 智能体技能实现工作流程自动化

NVIDIA/nurec-skills 资源库将主要步骤打包成智能体技能。编码智能体可以使用物理 AI 数据集定位和下载场景,使用 nre 渲染场景,并使用 nurec-fixer 优化输出。

有关端到端示例,请观看神经重建代理技能直播。

视频 1. 了解 NVIDIA Omniverse NuRec 如何使用 3D Gaussian splatting 重建现实世界的驾驶场景,并为智能汽车模拟进行渲染

公共 NVIDIA/nurec-skills 资源库包含使用 NCore 查找物理 AI 数据集、运行 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. 所需元数据文件、其内容和典型来源

本教程中使用的配套转换器和重建 recipe 需要使用所有三个 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
Camera-to-rig extrinsics PosesComponent:T_sensor_rig
指标自运动 PosesComponent:T_rig_world
可选全局参考 PosesComponent:T_world_world_global
自我口罩 MasksComponent
物体观察和追踪 CuboidsComponent
表 2. 将源数据映射到 NCore V4 组件

遵循公开的 NCore 坐标约定:

  • 装备:+X forward、+Y left、+Z up
  • 摄像头:+X (右侧) ,+Y (向下) ,+Z (向前)
  • 时间:整数微秒
  • 距离:米;姿势:有效的 SE (3) 转换

在 float64 中保留姿态计算。对本地“世界”帧进行变基,使第一个装备姿态成为身份。对于没有录制帧时间的同步恒定帧速率视频,帧`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
└── ... one camera archive per converted camera

共享的`<sequence-id>.ncore4.zarr.itar` 存档包含姿势、内部构造、遮罩和立方体等组件。每个`<sequence-id>.ncore4- <camera-id>.zarr.itar` 存档均包含一个转换后相机的帧。JSON 清单和所有引用的存档文件构成一个逻辑序列;它们必须保持在一起。

生成 NuRec 辅助数据

转换后的 NCore 序列包含记录的传感器测量、校准、姿态和物体追踪。它尚未包含此摄像头重建工作流程所需的推理语义分割、深度和自我掩码。公共 技能/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 由于工作流程中不包含激光雷达数据,因此禁用激光雷达分割
表 3. 辅助数据选项和生成的产品

省略 --camera-id,使用清单中的逻辑摄像头 ID,为每个摄像头处理在 NCORE_SEQUENCE_JSON. Selecting specific cameras requires one --camera-id=<logical-camera-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

开始使用

使用以下资源开始根据目标轮廓调整重建的场景。

公共软件、容器、数据集和模型构件需要拥有适用的 NVIDIA NGC 或 Hugging Face 账户并接受其许可证。NGC 上的 nre-ga 容器中提供了 NuRec 运行时。

标签