Air_Writing_Recognition / core /hand_tracker.py
Subiksha0515's picture
Update core/hand_tracker.py
4104c14 verified
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
# 🔥 smoothing memory
self.prev_x = None
self.prev_y = None
self.alpha = 0.85 # smoothing strength
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)
# 🔥 JITTER FILTER (ignore micro movement)
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
# 🔥 SMOOTHING FILTER
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)
)
# Finger states
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
# WRITE (pinch)
if pinch_dist < 30:
gesture = self.WRITE
self.click_start = 0
# CLICK
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