hand.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. from src.tracker import GestureTracker, Gesture
  2. from src.geometry import Positionable
  3. class HandGesture(Gesture):
  4. def __init__(self, hand, finger=None):
  5. self.hand = hand
  6. self.finger = finger
  7. def get_hand(self):
  8. return self.hand
  9. def get_finger(self):
  10. return self.finger
  11. class HandDownGesture(HandGesture):
  12. _type = 'hand_down'
  13. class HandUpGesture(HandGesture):
  14. _type = 'hand_up'
  15. class FingerDownGesture(HandGesture):
  16. _type = 'finger_down'
  17. class FingerMoveGesture(HandGesture):
  18. _type = 'finger_move'
  19. class FingerUpGesture(HandGesture):
  20. _type = 'finger_up'
  21. class Hand(Positionable):
  22. def __init__(self):
  23. self.fingers = []
  24. self.centroid = None
  25. def __len__(self):
  26. return len(self.fingers)
  27. def __iter__(self):
  28. return iter(self.fingers)
  29. def __str__(self):
  30. return '<Hand fingers=%s centroid=%s>' \
  31. % (self.fingers, self.get_centroid())
  32. def __repr__(self):
  33. return str(self)
  34. def add_finger(self, finger):
  35. self.fingers.append(finger)
  36. self.update_centroid()
  37. def remove_finger(self, finger):
  38. self.fingers.remove(finger)
  39. self.update_centroid()
  40. def update_centroid(self):
  41. l = len(self.fingers)
  42. if not l:
  43. self.centroid = None
  44. return
  45. coords = [f.get_position() for f in self.fingers]
  46. all_x, all_y = zip(*coords)
  47. self.centroid = sum(all_x) / l, sum(all_y) / l
  48. def get_centroid(self):
  49. return self.centroid
  50. class HandTracker(GestureTracker):
  51. supported_gestures = [HandDownGesture, HandUpGesture, FingerDownGesture,
  52. FingerMoveGesture, FingerUpGesture]
  53. configurable = ['max_finger_distance']
  54. def __init__(self, area):
  55. super(HandTracker, self).__init__(area)
  56. # Map of finger id's to corresponding hand objects
  57. self.finger_hands = {}
  58. # All hands being tracked
  59. self.hands = []
  60. # Maximum distance between two fingers to be assigned to the same hand
  61. self.max_finger_distance = 300
  62. def find_hand(self, finger):
  63. min_dist = hand = None
  64. for h in self.hands:
  65. dist = finger.distance_to(h.get_centroid())
  66. if min_dist is None or dist < min_dist:
  67. min_dist = dist
  68. hand = h
  69. if not hand or min_dist > self.max_finger_distance:
  70. hand = Hand()
  71. self.hands.append(hand)
  72. self.finger_hands[finger.get_id()] = hand
  73. hand.add_finger(finger)
  74. if len(hand) == 1:
  75. self.trigger(HandDownGesture(hand))
  76. return hand
  77. def on_point_down(self, event):
  78. finger = event.get_touch_object()
  79. hand = self.find_hand(finger)
  80. self.trigger(FingerDownGesture(hand, finger))
  81. def on_point_move(self, event):
  82. finger = event.get_touch_object()
  83. if finger.get_id() not in self.finger_hands:
  84. return
  85. hand = self.finger_hands[finger.get_id()]
  86. hand.update_centroid()
  87. if finger.distance_to(hand.get_centroid()) > self.max_finger_distance:
  88. hand.remove_finger(finger)
  89. if not len(hand):
  90. self.hands.remove(hand)
  91. self.trigger(HandUpGesture(hand))
  92. hand = self.find_hand(finger)
  93. self.trigger(FingerMoveGesture(hand, finger))
  94. def on_point_up(self, event):
  95. finger = event.get_touch_object()
  96. finger_id = finger.get_id()
  97. if finger_id not in self.finger_hands:
  98. return
  99. hand = self.finger_hands[finger_id]
  100. del self.finger_hands[finger_id]
  101. hand.remove_finger(finger)
  102. self.trigger(FingerUpGesture(hand, finger))
  103. if not len(hand):
  104. self.hands.remove(hand)
  105. self.trigger(HandUpGesture(hand))