支持主机桥接后固定δt与旋转先验,并落盘运动对供可视化直读。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+49
-4
@@ -19,10 +19,7 @@ import numpy as np
|
||||
from .contracts import LidarFrame
|
||||
|
||||
|
||||
def load_lidar_frames(path: Path | str) -> list[LidarFrame]:
|
||||
"""Load all LiDAR frames listed by ``frames_index.csv`` under ``path``."""
|
||||
|
||||
root = Path(path)
|
||||
def _read_frames_index(root: Path) -> tuple[np.ndarray, str]:
|
||||
index_path = root / "frames_index.csv"
|
||||
if not index_path.exists():
|
||||
raise FileNotFoundError(f"missing frames_index.csv under {root}")
|
||||
@@ -38,6 +35,54 @@ def load_lidar_frames(path: Path | str) -> list[LidarFrame]:
|
||||
raise ValueError(
|
||||
f"frames_index.csv must contain frame_id,{file_key}/filename,t_start,t_end; got {sorted(names)}"
|
||||
)
|
||||
return rows, file_key
|
||||
|
||||
|
||||
def list_lidar_frame_entries(path: Path | str) -> list[tuple[str, float, float, Path]]:
|
||||
"""Return ``(frame_id, t_start, t_end, npz_path)`` sorted by mid time (same as ``load_lidar_frames``)."""
|
||||
|
||||
root = Path(path)
|
||||
rows, file_key = _read_frames_index(root)
|
||||
entries: list[tuple[str, float, float, Path]] = []
|
||||
for row in rows:
|
||||
t0 = float(row["t_start"])
|
||||
t1 = float(row["t_end"])
|
||||
entries.append((str(row["frame_id"]), t0, t1, root / str(row[file_key])))
|
||||
entries.sort(key=lambda item: 0.5 * (item[1] + item[2]))
|
||||
return entries
|
||||
|
||||
|
||||
def load_lidar_frame_at(root: Path | str, index: int) -> LidarFrame:
|
||||
"""Load one frame by index in mid-time-sorted order (matches motion-pair ``i``/``j``)."""
|
||||
|
||||
entries = list_lidar_frame_entries(root)
|
||||
if index < 0 or index >= len(entries):
|
||||
raise IndexError(f"frame index {index} outside [0, {len(entries) - 1}] for {root}")
|
||||
frame_id, t0, t1, npz_path = entries[index]
|
||||
with np.load(npz_path) as payload:
|
||||
if "points" not in payload.files:
|
||||
raise ValueError(f"{npz_path} must contain array 'points'")
|
||||
points = np.asarray(payload["points"], dtype=float)
|
||||
if points.ndim != 2 or points.shape[1] < 3:
|
||||
raise ValueError(f"{npz_path}: points must have shape (N, 3[+])")
|
||||
return LidarFrame(
|
||||
frame_id=frame_id,
|
||||
t_start_s=t0,
|
||||
t_end_s=t1,
|
||||
points_xyz=points[:, :3],
|
||||
path=npz_path,
|
||||
)
|
||||
|
||||
|
||||
def lidar_frame_count(path: Path | str) -> int:
|
||||
return len(list_lidar_frame_entries(path))
|
||||
|
||||
|
||||
def load_lidar_frames(path: Path | str) -> list[LidarFrame]:
|
||||
"""Load all LiDAR frames listed by ``frames_index.csv`` under ``path``."""
|
||||
|
||||
root = Path(path)
|
||||
rows, file_key = _read_frames_index(root)
|
||||
|
||||
frames: list[LidarFrame] = []
|
||||
for row in rows:
|
||||
|
||||
Reference in New Issue
Block a user