File size: 1,381 Bytes
9f85448
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from __future__ import annotations

from dataclasses import dataclass

import numpy as np

WRIST = 0
THUMB_CMC, THUMB_MCP, THUMB_IP, THUMB_TIP = 1, 2, 3, 4
INDEX_MCP, INDEX_PIP, INDEX_DIP, INDEX_TIP = 5, 6, 7, 8
MIDDLE_MCP, MIDDLE_PIP, MIDDLE_DIP, MIDDLE_TIP = 9, 10, 11, 12
RING_MCP, RING_PIP, RING_DIP, RING_TIP = 13, 14, 15, 16
PINKY_MCP, PINKY_PIP, PINKY_DIP, PINKY_TIP = 17, 18, 19, 20

HAND_CONNECTIONS: tuple[tuple[int, int], ...] = (
    (0, 1), (1, 2), (2, 3), (3, 4),
    (0, 5), (5, 6), (6, 7), (7, 8),
    (5, 9), (9, 10), (10, 11), (11, 12),
    (9, 13), (13, 14), (14, 15), (15, 16),
    (13, 17), (17, 18), (18, 19), (19, 20),
    (0, 17),
)


@dataclass
class Hand:
    """One detected hand."""

    keypoints: np.ndarray
    scores: np.ndarray
    box: np.ndarray
    conf: float

    @property
    def scale(self) -> float:
        """Characteristic hand size."""
        palm = np.linalg.norm(self.keypoints[MIDDLE_MCP] - self.keypoints[WRIST])
        if palm < 1e-3:
            palm = max(self.box[2] - self.box[0], self.box[3] - self.box[1]) * 0.5
        return float(max(palm, 1e-3))

    @property
    def center(self) -> np.ndarray:
        """Palm center point."""
        return self.keypoints[[WRIST, INDEX_MCP, PINKY_MCP]].mean(axis=0)

    def point(self, idx: int) -> np.ndarray:
        """Keypoint by index."""
        return self.keypoints[idx]