| import cv2 |
| import math |
| import time |
| import os |
| import mediapipe as mp |
|
|
| from mediapipe.tasks.python import vision |
| from mediapipe.tasks import python |
|
|
|
|
| class HandTracker: |
|
|
| WRITE = "WRITE_GESTURE" |
| CLICK = "CLICK_GESTURE" |
| IGNORE = "IGNORE_GESTURE" |
|
|
| def __init__(self): |
|
|
| model_path = os.path.join(os.getcwd(), "hand_landmarker.task") |
|
|
| base_options = python.BaseOptions(model_asset_path=model_path) |
|
|
| options = vision.HandLandmarkerOptions( |
| base_options=base_options, |
| num_hands=1, |
| running_mode=vision.RunningMode.IMAGE, |
| min_hand_detection_confidence=0.7, |
| min_hand_presence_confidence=0.7, |
| min_tracking_confidence=0.7 |
| ) |
|
|
| self.detector = vision.HandLandmarker.create_from_options(options) |
|
|
| self.click_start = 0 |
| self.click_delay = 0.4 |
|
|
| |
| self.prev_x = None |
| self.prev_y = None |
| self.alpha = 0.85 |
|
|
| def get_gesture(self, frame): |
|
|
| rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) |
|
|
| mp_image = mp.Image( |
| image_format=mp.ImageFormat.SRGB, |
| data=rgb |
| ) |
|
|
| result = self.detector.detect(mp_image) |
|
|
| if not result.hand_landmarks: |
| self.click_start = 0 |
| self.prev_x = None |
| self.prev_y = None |
| return None, None |
|
|
| hand = result.hand_landmarks[0] |
| h, w, _ = frame.shape |
|
|
| x = int(hand[8].x * w) |
| y = int(hand[8].y * h) |
|
|
| |
| if self.prev_x is not None: |
| if abs(x - self.prev_x) < 3 and abs(y - self.prev_y) < 3: |
| x = self.prev_x |
| y = self.prev_y |
|
|
| |
| if self.prev_x is None: |
| smooth_x = x |
| smooth_y = y |
| else: |
| smooth_x = int(self.prev_x * self.alpha + x * (1 - self.alpha)) |
| smooth_y = int(self.prev_y * self.alpha + y * (1 - self.alpha)) |
|
|
| self.prev_x = smooth_x |
| self.prev_y = smooth_y |
|
|
| index_tip = (smooth_x, smooth_y) |
|
|
| thumb_tip = ( |
| int(hand[4].x * w), |
| int(hand[4].y * h) |
| ) |
|
|
| |
| fingers = [] |
| fingers.append(hand[8].y < hand[6].y) |
| fingers.append(hand[12].y < hand[10].y) |
| fingers.append(hand[16].y < hand[14].y) |
| fingers.append(hand[20].y < hand[18].y) |
|
|
| fingers_open = sum(fingers) |
|
|
| pinch_dist = math.hypot( |
| index_tip[0] - thumb_tip[0], |
| index_tip[1] - thumb_tip[1] |
| ) |
|
|
| gesture = self.IGNORE |
|
|
| |
| if pinch_dist < 30: |
| gesture = self.WRITE |
| self.click_start = 0 |
|
|
| |
| elif fingers_open == 1: |
| if self.click_start == 0: |
| self.click_start = time.time() |
| elif time.time() - self.click_start > self.click_delay: |
| gesture = self.CLICK |
|
|
| else: |
| gesture = self.IGNORE |
| self.click_start = 0 |
|
|
| return index_tip, gesture |