Source code for handposeutils.data.handpose

from typing import List, Literal, Dict
from .coordinate import Coordinate
from .constants import POINTS_NAMES_LIST, FINGER_MAPPING
from handposeutils.calculations import transforms


[docs] class HandPose: """ Represents a single 3D hand pose with 21 landmarks in MediaPipe format. Each landmark is stored along with its coordinate, side (left or right hand), common anatomical name, and the finger grouping it belongs to. Parameters ---------- coordinates : list of Coordinate A list of exactly 21 `Coordinate` objects representing the hand's landmarks. side : {'left_hand', 'right_hand'} The handedness of the pose. name : str, optional An optional identifier for the pose. Raises ------ ValueError If `coordinates` does not contain exactly 21 elements. """ def __init__(self, coordinates: List[Coordinate], side: Literal["left_hand", "right_hand"], name: str = None): if len(coordinates) != 21: raise ValueError("Expected 21 coordinates for hand landmarks (MediaPipe format).") self.side = side self.name = name # Optional identifier for the pose self.points: Dict[int, Dict] = {} for i, coord in enumerate(coordinates): finger = next((fname for fname, idxs in FINGER_MAPPING.items() if i in idxs), "PALM") self.points[i] = { "coordinate": coord, "side": side, "common_name": POINTS_NAMES_LIST[i], "finger": finger }
[docs] def get_coordinate_by_index(self, index: int) -> Coordinate: """ Retrieve a coordinate by its landmark index. Parameters ---------- index : int The landmark index (0–20). Returns ------- Coordinate The coordinate object at the specified index. """ return self.points[index]["coordinate"]
[docs] def get_index_by_common_name(self, name: str) -> int: """ Get the landmark index for a given common anatomical name. Parameters ---------- name : str The common name of the landmark (e.g., "WRIST", "INDEX_FINGER_TIP"). Returns ------- int The index (0–20) of the landmark. Raises ------ ValueError If no landmark with the given name is found. """ for i, data in self.points.items(): if data["common_name"] == name: return i raise ValueError(f"No point found with common name {name}")
[docs] def get_all_coordinates(self) -> List[Coordinate]: """ Get all coordinates for this hand pose. Returns ------- list of Coordinate All 21 coordinates in index order. """ return [self.points[i]["coordinate"] for i in range(21)]
[docs] def get_handedness(self) -> Literal["left_hand", "right_hand"]: """ Get the handedness of the pose. Returns ------- {'left_hand', 'right_hand'} The handedness of this pose. """ return self.side
def __str__(self): """ Return a human-readable string representation of the pose. Returns ------- str String showing the handedness and number of landmarks. """ return f"<HandPose {self.side}, {len(self.points)} landmarks>" def __getitem__(self, index_or_name: int | str) -> Coordinate: """ Retrieve a coordinate by index or common name. Parameters ---------- index_or_name : int or str The landmark index (0–20) or the common name of the landmark. Returns ------- Coordinate The coordinate object. Raises ------ TypeError If the input is neither an integer nor a string. ValueError If the string does not match any landmark common name. """ if isinstance(index_or_name, int): return self.get_coordinate_by_index(index_or_name) elif isinstance(index_or_name, str): idx = self.get_index_by_common_name(index_or_name) return self.get_coordinate_by_index(idx) raise TypeError("Index must be int (0–20) or common_name string.")
[docs] def normalize(self) -> "HandPose": """ Normalize the pose in both position and scale. Returns ------- HandPose A new normalized `HandPose` instance. """ return transforms.normalize_handpose(self)
[docs] def normalize_scaling(self) -> "HandPose": """ Normalize the scale of the pose (without changing position). Returns ------- HandPose A new `HandPose` instance scaled to a standard size. """ return transforms.normalize_handpose_scaling(self)
[docs] def normalize_position(self) -> "HandPose": """ Normalize the position of the pose (without scaling). Returns ------- HandPose A new `HandPose` instance translated to a standard position. """ return transforms.normalize_handpose_positioning(self)
[docs] def mirror(self, axis: Literal['x', 'y', 'z'] = 'x') -> "HandPose": """ Mirror the pose across a specified axis. Parameters ---------- axis : {'x', 'y', 'z'}, default='x' The axis to mirror across. Returns ------- HandPose A new mirrored `HandPose` instance. """ return transforms.mirror_pose(self, axis)
[docs] def rotate(self, degrees: float, axis: Literal['x', 'y', 'z'] = 'z') -> "HandPose": """ Rotate the pose around a specified axis. Parameters ---------- degrees : float The angle of rotation in degrees. axis : {'x', 'y', 'z'}, default='z' The axis to rotate around. Returns ------- HandPose A new rotated `HandPose` instance. """ return transforms.rotate_pose_by_axis(self, degrees, axis)
[docs] def straighten_finger(self, finger: str) -> "HandPose": """ Straighten the specified finger in the pose. Parameters ---------- finger : str The name of the finger to straighten (e.g., "INDEX", "THUMB"). Returns ------- HandPose A new `HandPose` instance with the specified finger straightened. """ return transforms.straighten_finger(self, finger)