GUI for finger v1
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
"""Finger example pipeline: runtime acquisition without GUI dependencies."""
|
||||
|
||||
from .config import PipelineConfig, mesh_threshold
|
||||
from .frame import FingerFrameView
|
||||
from .service import FingerPipeline
|
||||
|
||||
__all__ = [
|
||||
"FingerFrameView",
|
||||
"FingerPipeline",
|
||||
"PipelineConfig",
|
||||
"mesh_threshold",
|
||||
]
|
||||
@@ -0,0 +1,46 @@
|
||||
"""Configuration for the finger tactile example pipeline."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from viz.mesh_camera import DEFAULT_FINGER_VIZ_POSE
|
||||
|
||||
|
||||
def mesh_threshold(mesh_map: str, threshold: float | None) -> float:
|
||||
if threshold is not None:
|
||||
return threshold
|
||||
return 0.0 if mesh_map == "depth" else 0.4
|
||||
|
||||
|
||||
@dataclass
|
||||
class PipelineConfig:
|
||||
video: str = "0"
|
||||
config: str = "./config/dd02-ov.json"
|
||||
calib: str | None = None
|
||||
verbose: bool = False
|
||||
mesh_map: str = "depth"
|
||||
threshold: float | None = None
|
||||
viz_pose: str = DEFAULT_FINGER_VIZ_POSE
|
||||
enable_3d: bool = True
|
||||
use_color: bool = True
|
||||
lowpass_cutoff_hz: float = 5.0
|
||||
force_sample_rate_hz: float = 30.0
|
||||
|
||||
@classmethod
|
||||
def from_args(cls, args) -> "PipelineConfig":
|
||||
return cls(
|
||||
video=args.video,
|
||||
config=args.config,
|
||||
calib=getattr(args, "cal", None) or None,
|
||||
verbose=args.verbose,
|
||||
mesh_map=args.mesh_map,
|
||||
threshold=args.threshold,
|
||||
viz_pose=args.viz_pose,
|
||||
enable_3d=not args.no_3d,
|
||||
lowpass_cutoff_hz=getattr(args, "cutoff", 5.0),
|
||||
)
|
||||
|
||||
@property
|
||||
def flow_threshold(self) -> float:
|
||||
return mesh_threshold(self.mesh_map, self.threshold)
|
||||
@@ -0,0 +1,26 @@
|
||||
"""Display snapshot produced by one finger pipeline tick."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
@dataclass
|
||||
class FingerFrameView:
|
||||
timestamp: float
|
||||
fps: float
|
||||
unrolled: np.ndarray
|
||||
flow: np.ndarray
|
||||
vnormal: np.ndarray
|
||||
depth_map: np.ndarray
|
||||
img: np.ndarray
|
||||
contour: np.ndarray
|
||||
centroid: np.ndarray
|
||||
fnormal: float
|
||||
fshearx: float
|
||||
fsheary: float
|
||||
centroid_found: bool
|
||||
mask_coverage: float
|
||||
raw_frame: np.ndarray | None = None
|
||||
@@ -0,0 +1,123 @@
|
||||
"""Finger tactile acquisition loop for example dashboards."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
from orisys.finger import FingerRuntime
|
||||
|
||||
from viz import FrameRecorder, build_uv_surface_mesh, resolve_viz_pose_path
|
||||
|
||||
from .config import PipelineConfig
|
||||
from .frame import FingerFrameView
|
||||
|
||||
|
||||
class FingerPipeline:
|
||||
"""Owns FingerRuntime and produces FingerFrameView snapshots per tick."""
|
||||
|
||||
def __init__(self, config: PipelineConfig):
|
||||
self.config = config
|
||||
self.runtime: FingerRuntime | None = None
|
||||
self.recorder = FrameRecorder()
|
||||
self._start_time: float | None = None
|
||||
self.uv_mesh = None
|
||||
self.world_to_cam: np.ndarray | None = None
|
||||
self.mesh_lookat: np.ndarray | None = None
|
||||
|
||||
@property
|
||||
def is_open(self) -> bool:
|
||||
return self.runtime is not None
|
||||
|
||||
@property
|
||||
def tactile(self):
|
||||
if self.runtime is None:
|
||||
raise RuntimeError("FingerPipeline is not open")
|
||||
return self.runtime.tactile
|
||||
|
||||
def open(self) -> None:
|
||||
if self.runtime is not None:
|
||||
return
|
||||
self.runtime = FingerRuntime.open(
|
||||
config=self.config.config,
|
||||
calib=self.config.calib,
|
||||
video=self.config.video,
|
||||
verbose=self.config.verbose,
|
||||
)
|
||||
self._prepare_mesh_assets()
|
||||
self.runtime.warmup(color=self.config.use_color)
|
||||
self._start_time = time.time()
|
||||
|
||||
def _prepare_mesh_assets(self) -> None:
|
||||
if self.runtime is None:
|
||||
return
|
||||
domain = self.runtime.domain
|
||||
if domain.surface is None or getattr(domain.surface, "world_xyz", None) is None:
|
||||
return
|
||||
self.uv_mesh = build_uv_surface_mesh(domain.surface.world_xyz, domain.valid_mask)
|
||||
if self.config.viz_pose.lower() != "none":
|
||||
self.world_to_cam = np.load(resolve_viz_pose_path(self.config.viz_pose))
|
||||
self.mesh_lookat = self.uv_mesh.rest_vertices.mean(axis=0)
|
||||
|
||||
def close(self) -> None:
|
||||
if self.runtime is not None:
|
||||
self.runtime.close()
|
||||
self.runtime = None
|
||||
self._start_time = None
|
||||
|
||||
def reset(self) -> None:
|
||||
if self.runtime is not None:
|
||||
self.runtime.tactile.reset()
|
||||
|
||||
def tick(self) -> FingerFrameView | None:
|
||||
if self.runtime is None or self._start_time is None:
|
||||
return None
|
||||
|
||||
ok, unrolled = self.runtime.grab_and_process(color=self.config.use_color)
|
||||
if not ok:
|
||||
return None
|
||||
|
||||
tactile = self.runtime.tactile
|
||||
self.recorder.write_if_recording(tactile.frame)
|
||||
|
||||
tactile.compute_deformation(decompose=True, check_motion=True, threshold=0)
|
||||
tactile.compute_contact()
|
||||
|
||||
fps, flow, vnormal, img, contour, centroid, depth_map, fnormal, fshearx, fsheary = tactile.read_info(
|
||||
tactile.info.FPS,
|
||||
tactile.info.VRAW,
|
||||
tactile.info.VNORMAL,
|
||||
tactile.info.IMG,
|
||||
tactile.info.CONTOUR,
|
||||
tactile.info.CENTROID,
|
||||
tactile.info.DEPTH,
|
||||
tactile.info.FNORMAL,
|
||||
tactile.info.FSHEARX,
|
||||
tactile.info.FSHEARY,
|
||||
)
|
||||
|
||||
return FingerFrameView(
|
||||
timestamp=time.time() - self._start_time,
|
||||
fps=float(fps),
|
||||
unrolled=unrolled,
|
||||
flow=flow,
|
||||
vnormal=vnormal,
|
||||
depth_map=depth_map,
|
||||
img=img,
|
||||
contour=contour,
|
||||
centroid=centroid,
|
||||
fnormal=float(fnormal),
|
||||
fshearx=float(fshearx),
|
||||
fsheary=float(fsheary),
|
||||
centroid_found=bool(tactile.raw_sensor.centroid_found),
|
||||
mask_coverage=float(tactile.mask_stats["coverage"]),
|
||||
raw_frame=tactile.frame,
|
||||
)
|
||||
|
||||
def start_recording(self) -> bool:
|
||||
if self.runtime is None:
|
||||
return False
|
||||
return self.recorder.start(self.runtime.tactile.frame)
|
||||
|
||||
def stop_recording(self) -> None:
|
||||
self.recorder.stop()
|
||||
Reference in New Issue
Block a user