支持主机桥接后固定δt与旋转先验,并落盘运动对供可视化直读。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build motion_pairs.json next to an existing summary without re-solving extrinsic.
|
||||
|
||||
Use this once for older calibration outputs that predate automatic pair caching.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from imu_lidar.imu_audit import audit_imu
|
||||
from imu_lidar.imu_io import load_imu_samples
|
||||
from imu_lidar.keyframes import build_keyframes
|
||||
from imu_lidar.lidar_io import load_lidar_frames
|
||||
from imu_lidar.motion_pairs import build_motion_pairs
|
||||
from imu_lidar.motion_pairs_io import build_motion_pairs_payload, save_motion_pairs
|
||||
|
||||
|
||||
def _load_summary_meta(summary_path: Path) -> tuple[float, np.ndarray, str]:
|
||||
summary = json.loads(summary_path.read_text(encoding="utf-8"))
|
||||
delta_t = float(summary.get("time_offset_s") or 0.0)
|
||||
session = (summary.get("details") or {}).get("sessions", [{}])[0]
|
||||
session_id = str(session.get("session_id") or summary_path.parent.name)
|
||||
bias = np.asarray(
|
||||
(session.get("imu_audit") or {}).get("gyro_bias_rad_s")
|
||||
or (session.get("joint") or {}).get("gyro_bias_rad_s")
|
||||
or [0.0, 0.0, 0.0],
|
||||
dtype=float,
|
||||
).reshape(3)
|
||||
return delta_t, bias, session_id
|
||||
|
||||
|
||||
def export_one(
|
||||
*,
|
||||
lidar: Path,
|
||||
imu: Path,
|
||||
summary: Path,
|
||||
output: Path | None,
|
||||
min_rotation_deg: float,
|
||||
min_translation_m: float,
|
||||
) -> Path:
|
||||
delta_t, bias_from_summary, session_id = _load_summary_meta(summary)
|
||||
imu_series = load_imu_samples(imu)
|
||||
# Prefer freshly audited bias if summary bias is missing/zeros.
|
||||
if float(np.linalg.norm(bias_from_summary)) < 1e-12:
|
||||
bias = audit_imu(imu_series).gyro_bias_rad_s
|
||||
else:
|
||||
bias = bias_from_summary
|
||||
|
||||
frames = load_lidar_frames(lidar)
|
||||
keyframes = build_keyframes(
|
||||
frames,
|
||||
min_translation_m=min_translation_m,
|
||||
min_rotation_deg=min_rotation_deg,
|
||||
)
|
||||
pair_set = build_motion_pairs(
|
||||
session_id=session_id,
|
||||
keyframes=list(keyframes.frames),
|
||||
keyframe_indices=keyframes.indices,
|
||||
imu=imu_series,
|
||||
delta_t_s=delta_t,
|
||||
gyro_bias_rad_s=bias,
|
||||
min_rotation_deg=min_rotation_deg,
|
||||
min_translation_m=min_translation_m,
|
||||
)
|
||||
prepared = [
|
||||
{
|
||||
"session_id": session_id,
|
||||
"time_offset_s": delta_t,
|
||||
"gyro_bias_rad_s": np.asarray(bias, dtype=float).reshape(3),
|
||||
"pairs": pair_set.pairs,
|
||||
}
|
||||
]
|
||||
payload = build_motion_pairs_payload(prepared_sessions=prepared)
|
||||
out = output or (summary.parent / "motion_pairs.json")
|
||||
save_motion_pairs(out, payload)
|
||||
print(f"wrote {out} ({len(pair_set.pairs)} pairs, session={session_id}, dt={delta_t:.6f})")
|
||||
return out
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--lidar", type=Path, required=True)
|
||||
parser.add_argument("--imu", type=Path, required=True)
|
||||
parser.add_argument("--summary", type=Path, required=True)
|
||||
parser.add_argument("--output", type=Path, default=None, help="Default: <summary_dir>/motion_pairs.json")
|
||||
parser.add_argument("--min-pair-rotation-deg", type=float, default=2.0)
|
||||
parser.add_argument("--min-pair-translation-m", type=float, default=0.3)
|
||||
args = parser.parse_args()
|
||||
export_one(
|
||||
lidar=args.lidar,
|
||||
imu=args.imu,
|
||||
summary=args.summary,
|
||||
output=args.output,
|
||||
min_rotation_deg=args.min_pair_rotation_deg,
|
||||
min_translation_m=args.min_pair_translation_m,
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user