Skip to main content

calibrate-metropolis-camera

Extract camera intrinsics, extrinsics, and FOV polygons to calibration.json. Use after cameras are placed; to place them first use place-camera-max-coverage.

Datos de origen

Repositorio
isaac-sim/IsaacSim
Última actividad en el origen
18 de septiembre de 2026 a las 16:05
Idioma detectado de SKILL.md
inglés
Estrellas
4169
Forks
560

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Explorador de archivos
5 archivos

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
calibrate-metropolis-camera
description
Extract camera intrinsics, extrinsics, and FOV polygons to calibration.json. Use after cameras are placed; to place them first use place-camera-max-coverage.
license
Apache-2.0
metadata
{"author":"NVIDIA Isaac Sim <isaac-sim@nvidia.com>"}
# Calibrate Placed Cameras ## Purpose Produce a Metropolis-format `calibration.json` — per-camera intrinsics, extrinsics, homography, and field-of-view polygons — plus a top-view reference image, using `CameraCalibrationManager` from `isaacsim.sensors.rtx.calibration`. ## Prerequisites - Isaac Sim 6 / Kit 110 running with the Python server (`isaacsim.code_editor.python_server`, port 8226) — see `isaac-sim-remote`. - `isaacsim.sensors.rtx.calibration` resolvable. It is pinned by `isaacsim.exp.action_and_event_data_generation.base.kit`; launch that app, or `--enable isaacsim.sensors.rtx.calibration`. - **Cameras already placed** under the camera parent prim (default `/World/Cameras`) — use `place-camera-max-coverage` or `place-camera-aim-at` first. - A local output folder. Nucleus / cloud URIs are rejected. - Shell env contract from `isaac-sim-orchestrator`: `$ISAAC_SIM_DIR`, `$ISAAC_LAB_DIR`, `$WORKSPACE_DIR`. ## Limitations - **This repo does not build the extension.** `isaacsim.sensors.rtx.calibration` is authored in the `metrosim` repo and consumed here as an exact registry pin declared in `source/apps/isaacsim.exp.action_and_event_data_generation.base.kit` (read the version there rather than from this skill). This skill drives it; API changes belong upstream. - Needs a live Kit session — the top view is a real orthographic render, so there is no offline path. - Every camera must fall inside the top-view frustum. One camera outside it aborts the whole calibration. - The top-view camera path is stored in a **non-persistent** setting, so the top-view stage must be re-run each session before calibration. - Calibration describes cameras as they are *now*. Moving or re-placing a camera invalidates the file; re-run. ## Troubleshooting | Error / symptom | Cause | Solution | |---|---|---| | `CALIBRATE_PREFLIGHT: ext=unavailable` | App does not resolve the extension | Launch `isaacsim.exp.action_and_event_data_generation.base.sh`, or add `--enable isaacsim.sensors.rtx.calibration` | | `cameras=0` in preflight | Nothing under the camera parent prim | Place cameras first, or pass `camera_parent_prim_path` | | `place_info=invalid` | No usable `key=value` pair | Pass e.g. `place_info=room=warehouse`; pairs are joined with `/` | | `scene_root=missing` | `scene_root` does not resolve | Point it at a prim that bounds the area, usually `/World` | | "camera … is not covered by top view!" | A camera sits outside the top-view frustum | Widen `scene_root` to a prim whose bbox contains every camera, or remove the stray camera | | `calibration.json` not written | Pipeline aborted mid-run | Read the Isaac Sim console; the abort reason is logged via `carb.log_error` | | Calibration silently does nothing | Called the sync `generate_calibration()` | It is fire-and-forget; `await generate_calibration_async()` instead | | `if is_ready_to_calibrate():` never true | Returns `None` on success — see below | Compare `is not False`, never truthiness | ## When to use this skill | You want | Skill | |---|---| | `calibration.json` for cameras that already exist | **this skill** | | Decide *where* cameras go to cover an area | `place-camera-max-coverage` | | Decide *where* cameras go to watch one object | `place-camera-aim-at` | | Author one camera's intrinsics, AOVs, distortion by hand | `isaac-camera` | ## The pipeline Four stages, strictly ordered — each one depends on the previous having finished: 1. **Top-view camera.** An orthographic camera framed on `scene_root`. Sets `top_view_camera_path`, which every later stage validates. 2. **Calibration dots.** `dot_count` reference points per camera under `/World/Calibration_Dots`, used to solve the world↔image mapping. 3. **Calibration file.** Per-camera intrinsics, extrinsics, homography, and FOV polygons → `calibration.json`. 4. **Top-view image.** Orthographic render → `Top.png` plus `imageMetadata.json`. Parameter semantics and settings are in [`references/calibration-api.md`](references/calibration-api.md); the output schema and async/ordering rules are in [`references/calibration-runtime-notes.md`](references/calibration-runtime-notes.md). ## Available Scripts | Script | Purpose | Arguments | |---|---|---| | `scripts/calibrate_camera.py` | Extract intrinsics, extrinsics, and FOV polygons for placed cameras | injected `key=value` args (see script docstring) | ## Running scripts The script is a python_server payload, not a standalone program. From agent runtimes that expose skill execution helpers, invoke it with `run_script()`: ```python run_script("scripts/calibrate_camera.py", args=["action=preflight"]) ``` From a built tree, send it through the `isaac-sim-remote` client: ```bash python skills/isaac-sim-remote/scripts/isaacsim_send.py \ --file skills/calibrate-metropolis-camera/scripts/calibrate_camera.py \ --arg action=calibrate --arg output_dir=/tmp/calib ``` ## Workflow 1. **Preflight.** `action=preflight` (the default) reports extension, stage, camera count, `place_info`, `scene_root`, and output folder without touching the stage. It never raises. ```python run_script("scripts/calibrate_camera.py", args=["action=preflight"]) ``` Expect `CALIBRATE_PREFLIGHT: ext=enabled stage=ok cameras=5 place_info=ok scene_root=ok output_dir=...`. A `cameras=0` here is the usual blocker — place cameras first. 2. **Calibrate.** Runs all four stages and verifies the files landed. ```python run_script("scripts/calibrate_camera.py", args=["action=calibrate", "output_dir=/tmp/calib"]) ``` Expect `CALIBRATE_RESULT: action=calibrate cameras=5 top_camera=... output=/tmp/calib` followed by a `wrote <file> (<n> bytes)` line per artifact. 3. **Verify.** Confirm `calibration.json` has one `sensors[]` entry per camera and that `Top.png` is not black — a black top view means the orthographic camera framed empty space, and the homographies derived from it are meaningless. 4. **Re-run after any camera moves.** The file is a snapshot of the current poses. Use `action=topview` to refresh only the top-view camera and image without redoing the dots and calibration. ## Calling the API directly ```python from isaacsim.sensors.rtx.calibration import CameraCalibrationManager, CameraCalibrationSettings CameraCalibrationSettings.camera_calibration_output_folder_path = "/tmp/calib" CameraCalibrationSettings.place_info = "room=warehouse" CameraCalibrationSettings.scene_bounding_box_path = "/World" manager = CameraCalibrationManager.get_instance() manager.create_top_view_camera(root_prim_path="/World") await manager.generate_calibration_dot_prim_async() # NOT `if manager.is_ready_to_calibrate():` -- see below. if manager.is_ready_to_calibrate() is False: raise RuntimeError("stage is not ready; see the carb log") await manager.generate_calibration_async() await manager.capture_and_process_camera_view_image() ``` Three traps worth stating up front: - **`is_ready_to_calibrate()` returns `None` on success.** It has three `return False` branches and no `return True`, so it falls off the end. Testing it for truthiness means the guard never passes. Compare `is not False`. - **The sync entry points are fire-and-forget.** `generate_calibration()` wraps `asyncio.ensure_future(...)` and returns immediately, so the next stage races it. Await the `_async` variants; python_server payloads support top-level `await`. - **`top_view_camera_path` is non-persistent.** It is only set by `create_top_view_camera()`, so stage 1 must run every session even if the top-view camera prim still exists on the stage. ## Related skills - `place-camera-max-coverage` / `place-camera-aim-at` — produce the cameras this skill calibrates. - `isaac-sim-remote` — the transport this skill's script rides on. - `isaac-camera` — per-camera intrinsics, render products, AOVs, distortion. - `isaac-sim-sensor` — attaching annotators and writers once cameras exist.
Ver en GitHub