from src.tracker import GestureTracker, Gesture from src.geometry import Positionable class HandGesture(Gesture): def __init__(self, hand, finger=None): self.hand = hand self.finger = finger def get_hand(self): return self.hand def get_finger(self): return self.finger class HandDownGesture(HandGesture): _type = 'hand_down' class HandUpGesture(HandGesture): _type = 'hand_up' class FingerDownGesture(HandGesture): _type = 'finger_down' class FingerMoveGesture(HandGesture): _type = 'finger_move' class FingerUpGesture(HandGesture): _type = 'finger_up' class Hand(Positionable): def __init__(self): self.fingers = [] self.centroid = None def __len__(self): return len(self.fingers) def __iter__(self): return iter(self.fingers) def __str__(self): return '' \ % (self.fingers, self.get_centroid()) def __repr__(self): return str(self) def add_finger(self, finger): self.fingers.append(finger) self.update_centroid() def remove_finger(self, finger): self.fingers.remove(finger) self.update_centroid() def update_centroid(self): l = len(self.fingers) if not l: self.centroid = None return coords = [f.get_position() for f in self.fingers] all_x, all_y = zip(*coords) self.centroid = sum(all_x) / l, sum(all_y) / l def get_centroid(self): return self.centroid class HandTracker(GestureTracker): supported_gestures = [HandDownGesture, HandUpGesture, FingerDownGesture, FingerMoveGesture, FingerUpGesture] configurable = ['max_finger_distance'] def __init__(self, area): super(HandTracker, self).__init__(area) # Map of finger id's to corresponding hand objects self.finger_hands = {} # All hands being tracked self.hands = [] # Maximum distance between two fingers to be assigned to the same hand self.max_finger_distance = 300 def find_hand(self, finger): min_dist = hand = None for h in self.hands: dist = finger.distance_to(h.get_centroid()) if min_dist is None or dist < min_dist: min_dist = dist hand = h if not hand or min_dist > self.max_finger_distance: hand = Hand() self.hands.append(hand) self.finger_hands[finger.get_id()] = hand hand.add_finger(finger) if len(hand) == 1: self.trigger(HandDownGesture(hand)) return hand def on_point_down(self, event): finger = event.get_touch_object() hand = self.find_hand(finger) self.trigger(FingerDownGesture(hand, finger)) def on_point_move(self, event): finger = event.get_touch_object() if finger.get_id() not in self.finger_hands: return hand = self.finger_hands[finger.get_id()] hand.update_centroid() if finger.distance_to(hand.get_centroid()) > self.max_finger_distance: hand.remove_finger(finger) if not len(hand): self.hands.remove(hand) self.trigger(HandUpGesture(hand)) hand = self.find_hand(finger) self.trigger(FingerMoveGesture(hand, finger)) def on_point_up(self, event): finger = event.get_touch_object() finger_id = finger.get_id() if finger_id not in self.finger_hands: return hand = self.finger_hands[finger_id] del self.finger_hands[finger_id] hand.remove_finger(finger) self.trigger(FingerUpGesture(hand, finger)) if not len(hand): self.hands.remove(hand) self.trigger(HandUpGesture(hand))