feat(python): add Cosmos Transfer pipeline, docs, and smoke test (3/4)#9798
feat(python): add Cosmos Transfer pipeline, docs, and smoke test (3/4)#9798youtalk wants to merge 22 commits into
Conversation
Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Add an unordered_map<StencilId, unique_ptr<Stencil>> container to MapData with a const GetStencils() accessor, mirroring the existing signal/controller containers, matching the ue4-dev source of truth. Also add the prerequisite StencilId alias to RoadTypes.h (verbatim from ue4-dev). The earlier Stencil/RoadInfoStencil commit omitted it, so the new container would otherwise fail to compile (StencilId would resolve to the Stencil class, yielding a non-hashable map key). Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Port MapBuilder::SolveStencilReferencesAndTransforms() and ComputeStencilTransform() verbatim from ue4-dev and invoke the solver from Build() right after SolveSignalReferencesAndTransforms(). Without this finalization step _map_data._stencils was never populated (Map::GetStencils() returned empty), each RoadInfoStencil._stencil was left dangling, and Stencil._transform was never computed. Extend the stencil_parsing test to assert Map::GetStencils() is non-empty and that RoadInfoStencil::GetStencil() returns the linked Stencil, covering the linkage and the move that were previously untested. Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
The stencil_parsing test embeds the minimal OpenDRIVE inline via kStencilXodr (LIBCARLA_TEST_CONTENT_FOLDER is out-of-repo, so the on-disk fixture cannot be loaded by the test). The fixture file was therefore dead weight; remove it and drop the stale comment reference to minimize the PR diff. Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Port the Cosmos static-exporter base and the three clean exporters
(Crosswalks, TrafficSigns, WaitLines) from the ue4-dev branch into the
Unreal/CarlaUnreal Carla plugin.
The JSON serialization is preserved byte-for-byte; only include paths and
ue5 module conventions change, plus three forced ue5 API adaptations:
- Macro shims move from compiler/ to util/ and UE engine headers are
wrapped in util/ue-header-guard-{begin,end}.h.
- CrosswalksExporter: ACarlaGameModeBase::GetMap() now returns
std::optional (was boost::optional), and the data source is
road::Map::GetAllCrosswalkZones() (the ue4-only GetAllCrosswalksInfo()
does not exist on ue5-dev). The flat zone vertex list is re-split into
per-crosswalk polygons using the same triangle-fan / repeated-start-
vertex convention as road::Map::GetAllCrosswalkMesh, so each crosswalk
still produces one identical SHAPE3D label.
- TrafficSignsExporter: EInternalObjectFlags::AllFlags was removed in
UE 5.5; use the composite EInternalObjectFlags_AllFlags constant.
Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
…plugin Add the six exporter includes and the six BIND_SYNC(export_cosmos_*) handlers to CarlaServer.cpp, each dispatching to its exporter static method and returning the result string. RPC names match the Task 2.1 client names exactly. Fix the IWYU include order in the seven Cosmos exporter .cpp files so that each translation unit includes its own matching header first (before Carla.h), which UnrealBuildTool's IWYU check requires under bUseUnityBuild=false. Behavior and JSON output are unchanged. Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
The Carla UE plugin coding standard (CLAUDE.md) and the dominant ue5 convention require spaces, not tabs, for plugin code. The newly added Cosmos exporter files imported the ue4 tab style: CosmosStaticExporter.h (37 lines) and TrafficSignsExporter.h (19 lines) were tab-indented, the six other exporter headers each carried one stray tab-indented GENERATED_BODY() line, and CosmosStaticExporter.cpp had two tab-indented body lines. Re-indent all eight files with two spaces per level to match the surrounding ue5 plugin tree. This is a whitespace-only change (git diff --ignore-all-space is empty); no logic or JSON output is affected. Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
The traffic-signs exporter scanned the world's mesh components with GetObjectsOfClass(..., RF_ClassDefaultObject, EInternalObjectFlags_AllFlags). The fifth argument is the internal-flags *exclusion* mask, and the all-flags constant covers Native/RootSet/RefCounted/ReachableInCluster/..., which every in-world component carries. Passing it therefore excluded every live object, so the scan returned zero components and all three outputs (poles, traffic_signs, traffic_lights) were always empty. Set the exclusion mask back to the default EInternalObjectFlags::None so the scan sees live mesh components. On Town10HD_Opt this turns the previously empty exports into 120 poles, 162 traffic signs and 163 traffic lights. Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Add PythonAPI/test/smoke/test_cosmos_export.py, which drives all six world.export_cosmos_* RPCs against a running town and asserts each writes schema-correct JSON (top-level 'labels' array; non-empty for every exporter except road_markings, whose OpenDRIVE-stencil source may legitimately be empty on stock towns). The exporter writes the JSON server-side, so the test reconstructs the on-disk path(s) and reads them back (localhost-only); files are read as utf-8-sig because UE's ForceUTF8 prepends a BOM. The test self-skips when no CARLA server is reachable. Register it in smoke_test_list.txt. Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Copy the NVIDIA Cosmos Transfer example pipeline verbatim from ue4-dev into PythonAPI/examples/nvidia/cosmos (client/server scripts, conda YAMLs, Dockerfiles, and example_data with .mp4 artifacts, logs, and prompt TOMLs). The pipeline only calls world.export_cosmos_* plus standard sensors, so it is branch-independent. Register the cosmos-drive-dreams toolkit as a submodule pinned to the same commit ue4-dev tracks, and update the client README launch step from ./CarlaUE4.sh to the ue5-dev ./CarlaUnreal.sh package launch (with the source-build 'cmake --build Build/Development --target launch' equivalent). Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Port the NVIDIA Cosmos Transfer integration guide from ue4-dev, adapting the launch instruction to the UE5 packaged launch script (./CarlaUnreal.sh). Add the guide to the CARLA Ecosystem navigation and skip the cosmos_visualization control sensor in the sensor tick time smoke test. Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
The committed example_data .mp4/.log files are Git LFS pointer blobs, but the root .gitattributes only had '* text=auto' with no LFS rules, so git check-attr reported filter=unspecified and the LFS filter never applied. As a result git lfs push would not upload the referenced objects and git lfs pull would not fetch them, leaving the example videos/logs as orphaned pointer stubs after clone. Add the LFS routing rules (mirroring ue4-dev) so the *.mp4 and *.log filters resolve to lfs, and renormalize the affected paths so the index records them under the LFS filter. PNGs remain committed raw, consistent with ue4-dev. Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
The bundled InvertedAI example logs were recorded with CARLA 0.9.x and are not replayable on ue5-dev (0.10.0): show_recorder_file_info reports "Frames: 1, Duration: 0" and replay spawns no actors, because the per-frame recorder packet layout changed between 0.9.x and 0.10.0 (the file header still parses). Replace them with a working recording captured on Town10HD_Opt with the 0.10.0 recorder (hero actor id 298, 8 s @ 30 fps, ~40 vehicles), and regenerate the artifacts/ reference videos (rgb, edges, depth, instance_segmentation, semantic_segmentation, hdmap) from that log via carla_cosmos_gen.py + render_from_rds_hq.py. Update the README references and the example ego id accordingly. Verified end to end on ue5-dev: AOV capture, the six export_cosmos_* HD-map JSON exports, and the HD-map control video all render correctly. Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
Task 3.3 — Phase-1 exit gate: Cosmos restyle (Step 4c) ✅The final piece of the Phase-1 on-PC capture gate — the Cosmos Transfer style-conversion — is complete, so the end-to-end pipeline on this PR runs CARLA → control videos → Cosmos Transfer restyle. Server. A Cosmos Transfer1 server was deployed from the CARLA NVIDIA Brev launchable ( Inputs. The three control videos produced earlier on Config. Result. Cosmos Transfer produced a structure-preserving "steady rain" restyle: the road layout, lane markings, buildings and the lead vehicle are preserved while the scene is transformed to an overcast, wet, photorealistic look (wet road with tail-light reflections, darkened sky). Output video: H.264, 1280×704, 24 fps, 122 frames (~5 s). Generation took ~19 min on the single H100. CARLA input (left) vs Cosmos restyled (right):
Restyled video: rain_restyled.mp4With this, the Phase-1 verification gates for the Cosmos Transfer ue5-dev port are complete (capture + HD-map render + restyle here on #9798; in-editor materials/overlay on #9799). |

Description
This is PR 3 of a 4-PR stack that ports NVIDIA Cosmos Transfer support from
ue4-devtoue5-dev. It is stacked on top of PR 2 (#9797) and should be reviewed/merged bottom-up (PR1 #9796 → PR2 #9797 → this PR → PR4).PR3 adds the branch-independent Python client/server pipeline, documentation, and a smoke test that drive the C++ HD-map exporters introduced in PR2. None of this code depends on engine internals beyond the Python API already shipped by the lower PRs, so it can be reviewed largely on its own once the stack is in place.
What this PR adds:
PythonAPI/examples/nvidia/cosmos/client/.carla_cosmos_gen.pyreplays an InvertedAI log inside CARLA, captures the AOV (arbitrary-output-variable) frames — RGB, semantic segmentation, instance segmentation, depth, edges — and calls the sixWorld.export_cosmos_*RPCs from PR2 (export_cosmos_crosswalks,export_cosmos_road_boundaries,export_cosmos_lane_lines,export_cosmos_traffic_signs,export_cosmos_wait_lines,export_cosmos_road_markings) to emit the byte-compatible HD-map JSON, then renders the HD-map control video viarender_hdmap_video().cosmos_client.pysends the control inputs plus a text prompt to a Cosmos Transfer server and writes back the restyled result.cosmos_aov.yaml,sample_configs/,test_configs/), thecarla-cosmos-client.yamlconda environment,requirements_client.txt, the semantic-class filter, theprocess_prompts.shhelper, and a library of TOML scene prompts underexample_data/prompts/.PythonAPI/examples/nvidia/cosmos/server/:Dockerfile.serverandmake_docker.shto build the server image, thecarla-cosmos-server.yamlconda environment,requirements_server.txt,supervisord.conf, a Gradio app, and thecosmos-transfer1-utils/deploy/checkpoint/preprocess/transfer-pipeline helpers.example_data/media (committed via Git LFS): the InvertedAI input logs underlogs/inverted_ai/and the reference AOV / HD-map artifacts underartifacts/(rgb.mp4,semantic_segmentation.mp4,instance_segmentation.mp4,depth.mp4,edges.mp4,hdmap.mp4,vis.mp4)..gitattributesnow routes*.logand*.mp4through LFS.cosmos-drive-dreamssubmodule atPythonAPI/examples/nvidia/cosmos/utils/cosmos-drive-dreams(https://github.com/nv-tlabs/Cosmos-Drive-Dreams.git), which supplies the RDS-HQ rendering utilities used byrender_hdmap_video().Docs/nvidia_cosmos_transfer.md(with theDocs/img/cosmos_transfer/brev_01..07.pngscreenshots), plus the per-componentREADME.md/README_CLIENT.md/README_SERVER.md/RDS_HQ_GENERATION.md.mkdocs.ymlgains an "NVIDIA Cosmos Transfer" nav entry under the ecosystem section.PythonAPI/test/smoke/test_sensor_tick_time.pynow exercises thesensor.camera.cosmos_visualizationsensor alongside the other camera variants.Phase-1 on-PC capture (Task 3.3) — completed
The Phase 1 on-PC end-to-end capture has now been run on the full ue5-dev stack (PR1 #9796 + PR2 #9797 + PR3) on
Town10HD_Opt, with a headless editor (-game -RenderOffScreen -nosound -vulkan -carla-rpc-port=2000). The pipeline works end to end:ue5-devwith PR1 + PR2 + PR3 applied (PR3 adds no C++, so the PR2 editor build serves as the server).carla_cosmos_gen.pyto produce the AOV frames and the sixexport_cosmos_*HD-map JSONs — all valid RDS-HQlabels/shape3d, with real geometry on Town10HD_Opt (road_boundaries 231, lanelines 168, traffic_signs 162, crosswalks 16, wait_lines 15, road_markings 12; plus poles 120, traffic_lights 163), and 151 frames of camera poses + dynamic-object boxes + pinhole intrinsics.render_hdmap_video()(thecosmos-drive-dreamstoolkit) to render the HD-map control video — lane lines, road boundaries, crosswalks, signs, and dynamic-object boxes project correctly into the ego camera and align with the RGB.cosmos_client.pyrestyle — completed on a single H100; see the comment below for the restyle result and video.Captures
(a) AOV capture — RGB / Depth / Semantic Seg / Instance Seg / Canny Edges / Masked RGB:
(b) HD-map control video from the six
export_cosmos_*JSONs — RGB | HD-map | overlay:Part of #9795 (tracking issue: Port NVIDIA Cosmos Transfer support to ue5-dev).
Where has this been tested?
carlasim/carla-builder:ue5-22.04). The full end-to-end capture (Phase-1 on-PC gate above) was run on Ubuntu 24.04 (RTX 5090) on Town10HD_Opt: AOV frames + the six HD-map JSONs + the HD-map control video are verified; the Cosmos Transfer restyle was run on a single H100 (see comment below).Possible Drawbacks
example_data/media and InvertedAI logs are large and committed through Git LFS, so cloning the repo with LFS enabled pulls roughly 166 MB of additional objects.cosmos-drive-dreamssubmodule; contributors must rungit submodule update --initforrender_hdmap_video()to work.This change is