feat: add --cv-to-opengl option to apply_calibration_to_fusion_config.py
This commit is contained in:
@@ -23,6 +23,7 @@
|
|||||||
{"id":"py_workspace-kuy","title":"Move parquet documentation to docs/","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-07T02:52:12.609090777Z","created_by":"crosstyan","updated_at":"2026-02-07T02:52:43.088520272Z","closed_at":"2026-02-07T02:52:43.088520272Z","close_reason":"Moved parquet documentation to docs/marker-parquet-format.md"}
|
{"id":"py_workspace-kuy","title":"Move parquet documentation to docs/","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-07T02:52:12.609090777Z","created_by":"crosstyan","updated_at":"2026-02-07T02:52:43.088520272Z","closed_at":"2026-02-07T02:52:43.088520272Z","close_reason":"Moved parquet documentation to docs/marker-parquet-format.md"}
|
||||||
{"id":"py_workspace-kv8","title":"Update compare_pose_sets.py with Plotly visualization","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-08T07:55:38.911520186Z","created_by":"crosstyan","updated_at":"2026-02-08T07:57:13.711754402Z","closed_at":"2026-02-08T07:57:13.711754402Z","close_reason":"Added Plotly visualization to compare_pose_sets.py with camera frustums, axes, and ground plane overlay."}
|
{"id":"py_workspace-kv8","title":"Update compare_pose_sets.py with Plotly visualization","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-08T07:55:38.911520186Z","created_by":"crosstyan","updated_at":"2026-02-08T07:57:13.711754402Z","closed_at":"2026-02-08T07:57:13.711754402Z","close_reason":"Added Plotly visualization to compare_pose_sets.py with camera frustums, axes, and ground plane overlay."}
|
||||||
{"id":"py_workspace-ld1","title":"Search for depth unit conversion and scaling patterns","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-07T04:53:53.211242053Z","created_by":"crosstyan","updated_at":"2026-02-07T04:54:56.840335809Z","closed_at":"2026-02-07T04:54:56.840335809Z","close_reason":"Exhaustive search completed. Identified manual scaling in svo_sync.py and SDK-level scaling in depth_sensing.py. Documented risks in learnings.md."}
|
{"id":"py_workspace-ld1","title":"Search for depth unit conversion and scaling patterns","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-07T04:53:53.211242053Z","created_by":"crosstyan","updated_at":"2026-02-07T04:54:56.840335809Z","closed_at":"2026-02-07T04:54:56.840335809Z","close_reason":"Exhaustive search completed. Identified manual scaling in svo_sync.py and SDK-level scaling in depth_sensing.py. Documented risks in learnings.md."}
|
||||||
|
{"id":"py_workspace-lo0","title":"Add --cv-to-opengl option to apply_calibration_to_fusion_config.py","status":"closed","priority":2,"issue_type":"feature","owner":"crosstyan@outlook.com","created_at":"2026-02-09T03:33:40.435844317Z","created_by":"crosstyan","updated_at":"2026-02-09T03:34:37.514923778Z","closed_at":"2026-02-09T03:34:37.514923778Z","close_reason":"Added --cv-to-opengl option with matrix conversion logic and documentation."}
|
||||||
{"id":"py_workspace-nlu","title":"Produce A/B visualization comparison for CV world basis","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-08T03:50:56.386223999Z","created_by":"crosstyan","updated_at":"2026-02-08T03:52:41.232154353Z","closed_at":"2026-02-08T03:52:41.232154353Z","close_reason":"Generated A/B comparison images and analyzed visual differences. Source files remain unchanged."}
|
{"id":"py_workspace-nlu","title":"Produce A/B visualization comparison for CV world basis","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-08T03:50:56.386223999Z","created_by":"crosstyan","updated_at":"2026-02-08T03:52:41.232154353Z","closed_at":"2026-02-08T03:52:41.232154353Z","close_reason":"Generated A/B comparison images and analyzed visual differences. Source files remain unchanged."}
|
||||||
{"id":"py_workspace-nvw","title":"Update documentation for robust depth refinement","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-07T05:41:32.963615133Z","created_by":"crosstyan","updated_at":"2026-02-07T05:43:55.707975317Z","closed_at":"2026-02-07T05:43:55.707975317Z","close_reason":"Documentation updated with robust refinement details"}
|
{"id":"py_workspace-nvw","title":"Update documentation for robust depth refinement","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-07T05:41:32.963615133Z","created_by":"crosstyan","updated_at":"2026-02-07T05:43:55.707975317Z","closed_at":"2026-02-07T05:43:55.707975317Z","close_reason":"Documentation updated with robust refinement details"}
|
||||||
{"id":"py_workspace-q4w","title":"Add type hints and folder-aware --svo input in calibrate_extrinsics.py","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-06T10:01:13.943518267Z","created_by":"crosstyan","updated_at":"2026-02-06T10:03:09.855307397Z","closed_at":"2026-02-06T10:03:09.855307397Z","close_reason":"Implemented type hints and directory expansion for --svo"}
|
{"id":"py_workspace-q4w","title":"Add type hints and folder-aware --svo input in calibrate_extrinsics.py","status":"closed","priority":2,"issue_type":"task","owner":"crosstyan@outlook.com","created_at":"2026-02-06T10:01:13.943518267Z","created_by":"crosstyan","updated_at":"2026-02-06T10:03:09.855307397Z","closed_at":"2026-02-06T10:03:09.855307397Z","close_reason":"Implemented type hints and directory expansion for --svo"}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ Usage Example:
|
|||||||
import json
|
import json
|
||||||
import click
|
import click
|
||||||
import sys
|
import sys
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
def validate_pose_string(pose_str: str) -> bool:
|
def validate_pose_string(pose_str: str) -> bool:
|
||||||
@@ -76,9 +77,26 @@ def validate_pose_string(pose_str: str) -> bool:
|
|||||||
default=False,
|
default=False,
|
||||||
help="Fail if a calibration serial is missing in fusion config.",
|
help="Fail if a calibration serial is missing in fusion config.",
|
||||||
)
|
)
|
||||||
|
@click.option(
|
||||||
|
"--cv-to-opengl",
|
||||||
|
is_flag=True,
|
||||||
|
default=False,
|
||||||
|
help="Convert poses from OpenCV convention (Y-down, Z-forward) to OpenGL convention (Y-up, Z-backward).",
|
||||||
|
)
|
||||||
def main(
|
def main(
|
||||||
calibration_json: str, fusion_config_json: str, output_json: str, strict: bool
|
calibration_json: str,
|
||||||
|
fusion_config_json: str,
|
||||||
|
output_json: str,
|
||||||
|
strict: bool,
|
||||||
|
cv_to_opengl: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""
|
||||||
|
Apply calibration poses to a ZED Fusion configuration file.
|
||||||
|
|
||||||
|
If --cv-to-opengl is set, the T_world_from_cam matrix is converted from
|
||||||
|
OpenCV convention to OpenGL convention using T_gl = S @ T_cv @ S,
|
||||||
|
where S = diag(1, -1, -1, 1).
|
||||||
|
"""
|
||||||
with open(calibration_json, "r") as f:
|
with open(calibration_json, "r") as f:
|
||||||
calib_data: dict[str, dict[str, str]] = json.load(f)
|
calib_data: dict[str, dict[str, str]] = json.load(f)
|
||||||
|
|
||||||
@@ -108,6 +126,29 @@ def main(
|
|||||||
)
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
if cv_to_opengl:
|
||||||
|
# Convert OpenCV to OpenGL convention
|
||||||
|
# S = diag(1, -1, -1, 1)
|
||||||
|
# T_gl = S @ T_cv @ S
|
||||||
|
try:
|
||||||
|
vals = [float(p) for p in pose_str.split()]
|
||||||
|
t_cv = np.array(vals).reshape((4, 4))
|
||||||
|
|
||||||
|
# Validate it's a proper transform (roughly)
|
||||||
|
det = np.linalg.det(t_cv[:3, :3])
|
||||||
|
if not np.isclose(abs(det), 1.0, atol=1e-3):
|
||||||
|
click.echo(
|
||||||
|
f"Warning: Pose for {serial} may not be a valid rotation matrix (det={det:.4f})",
|
||||||
|
err=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
s = np.diag([1, -1, -1, 1])
|
||||||
|
t_gl = s @ t_cv @ s
|
||||||
|
pose_str = " ".join(f"{x:.8f}" for x in t_gl.flatten())
|
||||||
|
except Exception as e:
|
||||||
|
click.echo(f"Error converting pose for serial {serial}: {e}", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
if serial in fusion_data:
|
if serial in fusion_data:
|
||||||
if "FusionConfiguration" in fusion_data[serial]:
|
if "FusionConfiguration" in fusion_data[serial]:
|
||||||
fusion_data[serial]["FusionConfiguration"]["pose"] = pose_str
|
fusion_data[serial]["FusionConfiguration"]["pose"] = pose_str
|
||||||
|
|||||||
Reference in New Issue
Block a user