import numpy as np import json import cv2 from dataclasses import dataclass, field, asdict from typing import List, Optional, Tuple, Dict # ----- Helper Functions ----- def compute_distance(p1, p2): return np.hypot(p2[0] - p1[0], p2[1] - p1[1]) # 4) compute straightness per finger def finger_straight(i_tip, i_pip, i_mcp): d1 = np.hypot(*(np.array(i_tip)-np.array(i_pip))) d2 = np.hypot(*(np.array(i_pip)-np.array(i_mcp))) return float(np.clip(d1/(d2+1e-3), 0, 1)) def default_profile(): return [] @dataclass class CameraObject(): capture: Optional[cv2.VideoCapture] index: int pxHeight: int = 1536 pxWidth: int = 2048 # Calibration camera_matrix: Optional[np.ndarray] = None # 3x3 distortion_coefficients: Optional[np.ndarray] = None # 1x5 / 1x8 rotation_matrix_world_to_camera: Optional[np.ndarray] = None # 3x3 (world->cam) translation_vector_world_to_camera: Optional[np.ndarray] = None # 3x1 (world->cam) camera_projection_matrix: Optional[np.ndarray] = None def load_video_capture(self): #self.capture = cv2.VideoCapture(self.index, cv2.CAP_MSMF) self.capture = cv2.VideoCapture(self.index, cv2.CAP_ANY) #self.capture = cv2.VideoCapture(self.index, cv2.CAP_DSHOW) self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, 2048.0) self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 1536.0) @dataclass class Hand2D(): camera_id: str # e.g. "overhead_left" handedness: str # "Left" / "Right" score: float # detection/tracking confidence landmarks_px: np.ndarray # shape (21,2) in pixels @dataclass class CharucoDetection: camera_id: int # Output of Charuco detection charuco_corners: np.ndarray # (N, 1, 2) float32 charuco_ids: np.ndarray # (N, 1) int32 gray_frame: Optional[np.ndarray] = None @dataclass class CalibrationSample: detections: dict[int, CharucoDetection] # camera_id → detection