-
Notifications
You must be signed in to change notification settings - Fork 0
/
hands.py
139 lines (103 loc) · 4.12 KB
/
hands.py
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import cv2
import mediapipe as mp
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
class HandModel:
def __init__(self, handArray):
self.thumb = handArray[0]
self.index = handArray[1]
self.middle = handArray[2]
self.ring = handArray[3]
self.pinky = handArray[4]
self.name = ""
self.value = handArray[0:5]
def __eq__(self, other):
return self.thumb == other.thumb and self.index == other.index and self.middle == other.middle and self.ring == other.ring and self.pinky == other.pinky
class Fist(HandModel):
def __init__(self):
super().__init__([False, False, False, False, False])
self.name = "fist"
class Spread(HandModel):
def __init__(self):
super().__init__([False, True, True, True, True]) # Thumb is always false
self.name = "spread"
class Peace(HandModel):
def __init__(self):
super().__init__([False, True, True, False, False])
self.name = "peace"
class IndexFinger(HandModel):
def __init__(self):
super().__init__([False, True, False, False, False])
self.name = "index"
class MiddleFinger(HandModel):
def __init__(self):
super().__init__([False, False, True, False, False])
self.name = "middle"
class RingFinger(HandModel):
def __init__(self):
super().__init__([False, False, False, True, False])
self.name = "ring"
class PinkyFinger(HandModel):
def __init__(self):
super().__init__([False, False, False, False, True])
self.name = "pinky"
def handToName(arr: list[bool]):
for handType in [Fist(), Spread(), Peace(), IndexFinger(), MiddleFinger(), RingFinger(), PinkyFinger()]:
if arr == handType.value:
return handType.name
return "unknown"
mpHands = mp.solutions.hands
hands = mpHands.Hands(
static_image_mode=False,
max_num_hands=4,
min_detection_confidence=0.5,
min_tracking_confidence=0.3
)
mpDraw = mp.solutions.drawing_utils
def renderHandPoints(frame, results, debug):
if debug and results.multi_hand_landmarks:
for handLms in results.multi_hand_landmarks:
for id, lm in enumerate(handLms.landmark):
h, w, c = frame.shape
cx, cy = int(lm.x *w), int(lm.y*h)
cv2.circle(frame, (cx,cy), 3, (255,0,255), cv2.FILLED)
mpDraw.draw_landmarks(frame, handLms, mpHands.HAND_CONNECTIONS)
return frame
def fromList(l, a):
return [l[i] for i in a]
def getHandPoints(frame):
imgRGB = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = hands.process(imgRGB)
landmarks = results.multi_hand_landmarks
if landmarks:
return landmarks, results
return landmarks, results
def toVideospaceCoords(landmarks, width, height):
# Landmarks are from [-1 to 1], with x y and z. We need to convert this to the screen space coordinates
# of the camera, which is from [0 to width] and [0 to height]
# We need to convert the x and y coordinates to the screen space coordinates
# Z can be ignored
output = []
for landmark in landmarks:
x = int((landmark.x) * width)
y = int((landmark.y) * height)
output.append((x, y))
return output
import matplotlib.pyplot as plt
def getExtendedFingers(landmarks):
# Each finger is written as points [1,2,3,4], [5,6,7,8] etc
landmarks = landmarks.landmark
fingers = [landmarks[x:x + 4] for x in range(1, 20, 4)]
raised = [False for _ in range(5)]
for finger in fingers:
# Get the dot product of points 0 and 1 with 2 and 3
# If the dot product is negative, the finger is extended
# Get the vector from 0 to 1
vector1 = [finger[1].x - finger[0].x, finger[1].y - finger[0].y, finger[1].z - finger[0].z]
# Get the vector from 2 to 3
vector2 = [finger[3].x - finger[2].x, finger[3].y - finger[2].y, finger[3].z - finger[2].z]
# Get the dot product
dotProduct = vector1[0] * vector2[0] + vector1[1] * vector2[1] + vector1[2] * vector2[2]
# Set the variable
raised[fingers.index(finger)] = dotProduct
raised[0] = False
return raised