-
Notifications
You must be signed in to change notification settings - Fork 0
/
Gesture.py
210 lines (131 loc) · 5.6 KB
/
Gesture.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# *------------------------------------------------------------ *
# * Class: Gesture
# * --------------
# * class to represent a single gesture (as a list of poses)
# *
# *------------------------------------------------------------ *
#--- Standard ---
import os
import sys
import pickle
#--- Leap ---
sys.path.append ('/Users/jayhack/CS/NI/LeapDeveloperKit/LeapSDK/lib')
import Leap
#--- My Files ---
from common_utilities import print_message, print_status
from Position import Position
#--- Numpy ---
import numpy as np
# Class: Gesture
# --------------
# respresents a list of frames that can be classified as gestures
class Gesture:
name = '__UNCLASSIFIED__' # Name of this gesture
#--- Data ---
frames = [] # list of Leap 'Frame' objects constituting this gesture
O = [] # "Observations": list of vector-representations constituting this gesture
hmm_rep = [] # can be passed to an hmm
#--- Parameters ---
gesture_length = 30 # number of frames stored in the gesture
frame_reduction_const = 5 # gesture_length/frame_reduction_const = # of frames in final feature rep
d1_length = 5 # small derivative of motion
d2_length = 10 # large derivative of motion
# Function: Constructor
# ---------------------
# initializes an empty frame
def __init__ (self, name='__UNCLASSIFIED__', observations_filepath=None):
### Step 1: set/initialize data and parameters ###
self.name = name
self.frames = []
self.O = []
### Step 2: load the observations in, if appropriate ###
if observations_filepath:
self.load_observations(observations_filepath)
########################################################################################################################
########################################[ --- Getting Stats on Gesture --- ]###########################################
########################################################################################################################
# Function: is_full
# -----------------
# returns wether the gesture is full or not
def is_full (self):
return (len(self.O) >= self.gesture_length)
# Function: get_hmm_rep
# -------------------------
# returns a feature-vector representation of the gesture.
# this will be applied
def get_hmm_rep (self):
self.hmm_rep = []
### Step 1: add all frames appropriate for frame-reduction const ###
for i, O_i in enumerate(self.O):
if i % self.frame_reduction_const == 0:
self.hmm_rep.append (np.array(O_i))
### Step 2: add the very last frame ###
self.hmm_rep.append (np.array(self.O[-1]))
### Step 3: convert to numpy array and return ###
self.hmm_rep = np.array (self.hmm_rep)
return self.hmm_rep
########################################################################################################################
########################################[ --- Adding Frames --- ]######################################################
########################################################################################################################
# Function: pop_oldest_frame
# --------------------------
# pops off the oldest frame contained in this gesture
def pop_oldest_frame (self):
self.O.pop(0)
self.frames.pop (0)
# Function: get_prev_frames
# -------------------------
# gets the frames to use for first/second derivative features.
def get_prev_frames (self):
### Step 1: get the newest frame ###
newest_frame = self.frames[-1]
### Step 2: set d1_frame, d2_frame as frame if insuffucient
d1_frame = newest_frame
d2_frame = newest_frame
if len (self.O) > self.d1_length:
d1_frame = self.frames[-self.d1_length]
if len(self.O) > self.d2_length:
d2_frame = self.frames[-self.d2_length]
return (d1_frame, d2_frame)
# Function: add_frame
# -------------------
# takes in a Leap frame object and adds to the current gesture;
# removes excessive frames if necessary
# Note: should probably have a mechanism that clears the gesture if the hand disappears?
def add_frame (self, frame):
### Step 1: add to list of 'Frame' objects (self.frames) ###
self.frames.append (frame)
### Step 2: add to the list of observations (self.O) ###
(d1_frame, d2_frame) = self.get_prev_frames ()
position = Position (frame, d1_frame, d2_frame)
self.O.append (position.features)
### Step 3: if the hand was missing, reset the gesture (only consider sequences where we see the hand) ###
if position.features == None:
self.clear ()
return
### Step 5: remove frames if necessary ###
if len(self.O) > self.gesture_length:
self.pop_oldest_frame ()
# Function: clear
# ---------------
# clears the gesture. should be called after a classification goes through
def clear (self):
self.frames = []
self.O = []
########################################################################################################################
########################################[ --- Loading/Saving --- ]######################################################
########################################################################################################################
# Function: pickle_self
# ---------------------
# saves all data from this gesture
def pickle_self (self, save_filepath):
save_file = open(save_filepath, 'w')
pickle.dump (self.O, save_file)
save_file.close ()
# Function: load_observations
# ---------------------------
# loads in observations describing this gesture
def load_observations (self, observations_filepath):
open_file = open (observations_filepath, 'r')
self.O = pickle.load (open_file)
open_file.close ()