hand / gesture_logic.py
Neil67's picture
Deploy gesture image player
e47efb2 verified
Raw
History Blame Contribute Delete
2.71 kB
from collections import deque
import time
NEXT = "NEXT"
PREV = "PREV"
FIRST = "FIRST"
LAST = "LAST"
NONE = "NONE"
VALID_COMMANDS = {NEXT, PREV, FIRST, LAST, NONE}
HISTORY_SIZE = 6
SWIPE_DELTA_THRESHOLD = 0.08
COOLDOWN_SECONDS = 0.6
FINGER_CONFIRM_FRAMES = 2
_x_history = deque(maxlen=HISTORY_SIZE)
_last_command_time = 0.0
_first_hold_count = 0
_last_hold_count = 0
def _in_cooldown(now_ts: float) -> bool:
return (now_ts - _last_command_time) < COOLDOWN_SECONDS
def _register_command(command: str, now_ts: float) -> str:
global _last_command_time
_last_command_time = now_ts
_x_history.clear()
return command
def _finger_only_command(fingers: dict) -> str:
global _first_hold_count, _last_hold_count
index = fingers.get("index", False)
middle = fingers.get("middle", False)
ring = fingers.get("ring", False)
pinky = fingers.get("pinky", False)
# Thumb is noisy in webcam/selfie views, so we ignore thumb for FIRST/LAST.
only_index = index and (not middle) and (not ring) and (not pinky)
only_pinky = pinky and (not index) and (not middle) and (not ring)
if only_index:
_first_hold_count += 1
_last_hold_count = 0
if _first_hold_count >= FINGER_CONFIRM_FRAMES:
_first_hold_count = 0
return FIRST
return NONE
if only_pinky:
_last_hold_count += 1
_first_hold_count = 0
if _last_hold_count >= FINGER_CONFIRM_FRAMES:
_last_hold_count = 0
return LAST
return NONE
_first_hold_count = 0
_last_hold_count = 0
return NONE
def infer_gesture_command(hand_data) -> str:
"""
Infer command from tracked hand data.
Command priority:
1) Finger-only gestures (FIRST/LAST)
2) Swipe gestures (NEXT/PREV)
3) NONE
"""
now_ts = time.time()
if _in_cooldown(now_ts):
return NONE
if not hand_data or not hand_data.get("hand_found", False):
_x_history.clear()
return NONE
fingers = hand_data.get("fingers_extended", {})
finger_command = _finger_only_command(fingers)
if finger_command != NONE:
return _register_command(finger_command, now_ts)
center_x = hand_data.get("hand_center_x")
if center_x is None:
return NONE
_x_history.append(float(center_x))
if len(_x_history) < 3:
return NONE
delta_x = _x_history[-1] - _x_history[0]
if delta_x >= SWIPE_DELTA_THRESHOLD:
return _register_command(NEXT, now_ts)
if delta_x <= -SWIPE_DELTA_THRESHOLD:
return _register_command(PREV, now_ts)
return NONE
def is_valid_command(command: str) -> bool:
return command in VALID_COMMANDS