Files
orisys-sdk/src/orisys/finger/exports.py
T

109 lines
3.4 KiB
Python

from __future__ import annotations
import sys
from dataclasses import dataclass
from pathlib import Path
from ..configs import resolve_sensor_asset_dir
from ..unroll import (
compute_uv_distortion_metrics,
load_exported_data,
recommend_edge_expand,
scaled_map_cache_path,
)
DEFAULT_FINGER_EXPORT_DIR = "sensors/finger/assets/30fps-0703"
DEFAULT_FINGER_MAP_CACHE = f"{DEFAULT_FINGER_EXPORT_DIR}/unroll_map_uv.npz"
@dataclass(frozen=True)
class FingerExportPaths:
"""Resolved Blender export bundle paths for finger UV pipelines."""
export_dir: Path
mesh: Path
intrinsics: Path
pose: Path
def as_tuple(self) -> tuple[str, str, str]:
return (str(self.mesh), str(self.intrinsics), str(self.pose))
@dataclass(frozen=True)
class FingerExportBundle:
"""Loaded Blender export data and UV map-cache settings."""
export_paths: FingerExportPaths
data: dict
map_cache: str
edge_expand: float
def _candidate_export_dirs(export_dir) -> list[Path]:
raw = Path(export_dir).expanduser()
if raw.is_absolute():
return [raw]
here = Path(__file__).resolve()
candidates = []
bundled_assets = resolve_sensor_asset_dir("finger")
if bundled_assets is not None and raw.as_posix() == DEFAULT_FINGER_EXPORT_DIR:
candidates.append(bundled_assets)
candidates.extend([
Path.cwd() / raw,
here.parents[1] / raw, # packaged wheel filesystem layout
here.parents[3] / raw, # editable install: repo/assets/...
])
if getattr(sys, "frozen", False):
candidates.insert(0, Path(sys.executable).resolve().parent / raw)
unique: list[Path] = []
for candidate in candidates:
resolved = candidate.resolve()
if resolved not in unique:
unique.append(resolved)
return unique
def resolve_export_paths(export_dir) -> FingerExportPaths:
"""Return Blender export paths expected inside one folder."""
checked: list[str] = []
for root in _candidate_export_dirs(export_dir):
paths = FingerExportPaths(
export_dir=root,
mesh=root / "mesh.npz",
intrinsics=root / "camera_intrinsics.npz",
pose=root / "world_to_cam.npy",
)
missing = [name for name, path in vars(paths).items() if name != "export_dir" and not path.is_file()]
if not missing:
return paths
checked.append(f"{root} (missing: {', '.join(missing)})")
raise FileNotFoundError(
f"Missing export file(s) for finger bundle '{export_dir}'. "
f"Checked: {'; '.join(checked)}"
)
def load_finger_export_bundle(
export_dir,
*,
map_cache=DEFAULT_FINGER_MAP_CACHE,
source_scale=1.0,
) -> FingerExportBundle:
"""Resolve export paths, load bundle data, and pick the UV map cache path."""
export_paths = resolve_export_paths(export_dir)
if Path(map_cache) == Path(DEFAULT_FINGER_MAP_CACHE):
map_cache = str(export_paths.export_dir / "unroll_map_uv.npz")
map_cache = scaled_map_cache_path(map_cache, source_scale)
mesh_path, intrinsics_path, pose_path = export_paths.as_tuple()
data = load_exported_data(mesh_path, intrinsics_path, pose_path)
distortion = compute_uv_distortion_metrics(data)
edge_expand = recommend_edge_expand(distortion)
return FingerExportBundle(
export_paths=export_paths,
data=data,
map_cache=map_cache,
edge_expand=float(edge_expand),
)