From 18e814217ada9c525478df66ffbf1280a71f831f Mon Sep 17 00:00:00 2001 From: crosstyan Date: Sat, 7 Feb 2026 16:16:58 +0000 Subject: [PATCH] feat: add manual ground-plane overlay to visualize_extrinsics.py --- py_workspace/.beads/issues.jsonl | 1 + py_workspace/README.md | 11 ++++++++ py_workspace/visualize_extrinsics.py | 40 ++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/py_workspace/.beads/issues.jsonl b/py_workspace/.beads/issues.jsonl index bfb3217..c958855 100644 --- a/py_workspace/.beads/issues.jsonl +++ b/py_workspace/.beads/issues.jsonl @@ -1,6 +1,7 @@ {"id":"py_workspace-0mu","title":"Implement --render-space in visualize_extrinsics.py","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-07T16:08:12.543309499Z","created_by":"crosstyan","updated_at":"2026-02-07T16:08:17.303232927Z","closed_at":"2026-02-07T16:08:17.303232927Z","close_reason":"Implemented --render-space with opencv/opengl choices and updated README"} {"id":"py_workspace-0q7","title":"Fix basedpyright errors in aruco/pose_averaging.py","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-07T08:53:33.377735199Z","created_by":"crosstyan","updated_at":"2026-02-07T08:58:49.252312392Z","closed_at":"2026-02-07T08:58:49.252312392Z","close_reason":"Fixed basedpyright errors"} {"id":"py_workspace-214","title":"Migrate visualize_extrinsics to Plotly with diagnose mode","status":"closed","priority":2,"issue_type":"feature","owner":"crosstyan@outlook.com","created_at":"2026-02-07T15:14:40.547616056Z","created_by":"crosstyan","updated_at":"2026-02-07T15:25:00.354290874Z","closed_at":"2026-02-07T15:25:00.354290874Z","close_reason":"Fixed QA issues: Y-up enforcement, README sync, dependencies"} +{"id":"py_workspace-2c1","title":"Add manual ground-plane overlay to visualize_extrinsics.py","status":"open","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-07T16:15:17.432846006Z","created_by":"crosstyan","updated_at":"2026-02-07T16:15:17.432846006Z"} {"id":"py_workspace-62y","title":"Fix depth pooling fallback threshold","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-07T08:12:12.046607198Z","created_by":"crosstyan","updated_at":"2026-02-07T08:13:12.98625698Z","closed_at":"2026-02-07T08:13:12.98625698Z","close_reason":"Updated fallback threshold to strict comparison"} {"id":"py_workspace-6m5","title":"Robust Optimizer Implementation","status":"closed","priority":0,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-07T05:22:45.183574374Z","created_by":"crosstyan","updated_at":"2026-02-07T05:22:53.151871639Z","closed_at":"2026-02-07T05:22:53.151871639Z","close_reason":"Implemented robust optimizer with least_squares and soft_l1 loss, updated tests"} {"id":"py_workspace-6sg","title":"Document marker parquet structure","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-07T02:48:08.95742431Z","created_by":"crosstyan","updated_at":"2026-02-07T02:49:35.897152691Z","closed_at":"2026-02-07T02:49:35.897152691Z","close_reason":"Documented parquet structure in aruco/markers/PARQUET_FORMAT.md"} diff --git a/py_workspace/README.md b/py_workspace/README.md index 9bedb7a..0da6520 100755 --- a/py_workspace/README.md +++ b/py_workspace/README.md @@ -75,6 +75,17 @@ Use `--birdseye` for a top-down X-Z view (looking down Y axis). uv run visualize_extrinsics.py -i output/extrinsics.json --birdseye --show ``` +**Ground Plane Overlay:** +Render a semi-transparent X-Z ground plane to anchor camera poses. +- `--show-ground/--no-show-ground`: Toggle ground plane (default: show). +- `--ground-y FLOAT`: Set the Y height of the plane (default: 0.0). +- `--ground-size FLOAT`: Set the side length of the plane in meters (default: 8.0). + +*Example: Ground plane at Y=-1.5 with 10m size* +```bash +uv run visualize_extrinsics.py -i output/extrinsics.json --ground-y -1.5 --ground-size 10 --show +``` + **Using ZED Configs for Accurate Frustums:** Load intrinsics from ZED calibration files to render accurate frustum shapes. - **Directory**: Matches `SN.conf` files to camera serials in the JSON. diff --git a/py_workspace/visualize_extrinsics.py b/py_workspace/visualize_extrinsics.py index 11102c8..77eb5e4 100644 --- a/py_workspace/visualize_extrinsics.py +++ b/py_workspace/visualize_extrinsics.py @@ -457,6 +457,23 @@ def run_diagnostics(poses: Dict[str, np.ndarray], convention: str): is_flag=True, help="Run numerical diagnostics on the poses.", ) +@click.option( + "--show-ground/--no-show-ground", + default=True, + help="Show a ground plane at Y=ground-y.", +) +@click.option( + "--ground-y", + type=float, + default=0.0, + help="Y height of the ground plane.", +) +@click.option( + "--ground-size", + type=float, + default=8.0, + help="Size of the ground plane (side length in meters).", +) def main( input: str, output: Optional[str], @@ -471,6 +488,9 @@ def main( resolution: str, eye: str, diagnose: bool, + show_ground: bool, + ground_y: float, + ground_size: float, ): """Visualize camera extrinsics from JSON using Plotly.""" try: @@ -526,6 +546,26 @@ def main( intrinsics=cam_intrinsics, ) + if show_ground: + half_size = ground_size / 2.0 + x_grid = np.linspace(-half_size, half_size, 2) + z_grid = np.linspace(-half_size, half_size, 2) + x_mesh, z_mesh = np.meshgrid(x_grid, z_grid) + y_mesh = np.full_like(x_mesh, ground_y) + + fig.add_trace( + go.Surface( + x=x_mesh, + y=y_mesh, + z=z_mesh, + showscale=False, + opacity=0.15, + colorscale=[[0, "gray"], [1, "gray"]], + name="Ground Plane", + hoverinfo="skip", + ) + ) + # Configure layout scene_dict: Dict[str, Any] = dict( xaxis_title="X (m)",