From c72ff7ded0fdfeb292df2b7fc349370670978062 Mon Sep 17 00:00:00 2001 From: moscovskayaliza Date: Thu, 25 Jun 2026 10:42:40 +0300 Subject: [PATCH] fixed geom gestures --- gesture_control/special_gestures.py | 88 +++++++++++++++++------------ 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/gesture_control/special_gestures.py b/gesture_control/special_gestures.py index 0d30d1d..a0acafb 100644 --- a/gesture_control/special_gestures.py +++ b/gesture_control/special_gestures.py @@ -35,9 +35,9 @@ class SpecialGestureDetector: } # Повышенный порог уверенности для специальных жестов - min_conf = 0.6 + min_conf = 0.5 required = ['left_shoulder', 'right_shoulder', 'left_elbow', 'right_elbow', - 'left_wrist', 'right_wrist', 'left_hip', 'right_hip'] + 'left_wrist', 'right_wrist', 'nose'] for p in required: if landmarks[idx[p]][3] < min_conf: if self.debug: @@ -53,50 +53,64 @@ class SpecialGestureDetector: r_wr = landmarks[idx['right_wrist']][:2] l_hip = landmarks[idx['left_hip']][:2] r_hip = landmarks[idx['right_hip']][:2] - - hip_center = (l_hip + r_hip) / 2 + nose = np.array(landmarks[idx['nose']][:2]) + + shoulder_center_y = (l_sh[1] + r_sh[1]) / 2 + hip_center_y = (l_hip[1] + r_hip[1]) / 2 + torso_height = hip_center_y - shoulder_center_y shoulder_width = np.linalg.norm(r_sh - l_sh) - if shoulder_width < 50 or shoulder_width > 300: - if self.debug: - print("shoulder_width out of range") + if shoulder_width < 30 or torso_height < 10: return 'none' - # ----- КРЕСТ (предплечья скрещены на груди) ----- - # 1. Запястья перекрещены (левое правее правого) И на уровне груди (ниже плеч, выше бедер) - wrists_crossed = l_wr[0] > r_wr[0] - wrists_chest_level = (max(l_wr[1], r_wr[1]) > max(l_sh[1], r_sh[1]) and - min(l_wr[1], r_wr[1]) < hip_center[1]) - - # 2. Локти тоже на уровне груди (примерно) - elbows_chest_level = (max(l_el[1], r_el[1]) > max(l_sh[1], r_sh[1]) * 0.9 and - min(l_el[1], r_el[1]) < hip_center[1] * 1.1) + # ---- Вспомогательные функции ---- + def angle_between_vectors(v1, v2): + """Угол между двумя векторами в градусах (0..180)""" + cos_a = np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2) + 1e-6) + return np.arccos(np.clip(cos_a, -1.0, 1.0)) * 180 / np.pi - # 3. Руки согнуты (предплечья короче верхней части руки) - left_bent = np.linalg.norm(l_wr - l_el) < np.linalg.norm(l_el - l_sh) * 0.9 - right_bent = np.linalg.norm(r_wr - r_el) < np.linalg.norm(r_el - r_sh) * 0.9 - arms_bent = left_bent and right_bent + def elbow_angle(shoulder, elbow, wrist): + """Угол в локте (плечо-локоть-запястье)""" + v1 = shoulder - elbow + v2 = wrist - elbow + return angle_between_vectors(v1, v2) - # 4. Запястья близко к центру тела (не сильно отведены, типично для креста на груди) - body_center_x = (l_sh[0] + r_sh[0]) / 2 - wrists_near_center = (abs(l_wr[0] - body_center_x) < shoulder_width * 0.6 and - abs(r_wr[0] - body_center_x) < shoulder_width * 0.6) + # ---- Вычисляем углы ---- + l_angle = elbow_angle(l_sh, l_el, l_wr) # угол в левом локте + r_angle = elbow_angle(r_sh, r_el, r_wr) # угол в правом локте - cross = (wrists_crossed and wrists_chest_level and elbows_chest_level and - arms_bent and wrists_near_center) + # ---- КРЕСТ ---- + # 1. Оба локтя сильно согнуты (< 100°) + elbows_bent = (l_angle < 100 and r_angle < 100) + # 2. Левое запястье правее правого (перекрест) + wrists_crossed = l_wr[0] > r_wr[0] + 5 # небольшой запас в пикселях (можно и 0) + # 3. Запястья находятся между плечами и бёдрами по Y (уровень груди) + wrists_at_chest = ( + shoulder_center_y - 0.3 * torso_height < l_wr[1] < hip_center_y + 0.3 * torso_height and + shoulder_center_y - 0.3 * torso_height < r_wr[1] < hip_center_y + 0.3 * torso_height + ) - if self.debug and cross: - print(f"CROSS: crossed={wrists_crossed}, chest_w={wrists_chest_level}, " - f"chest_e={elbows_chest_level}, bent={arms_bent}, near_center={wrists_near_center}") + cross = elbows_bent and wrists_crossed and wrists_at_chest if cross: return 'cross' - # ----- ДОМИК (руки над головой) ----- - head_y = landmarks[idx['nose']][1] - 50 - arms_up = (l_wr[1] < head_y and r_wr[1] < head_y) - if arms_up: - dist = np.linalg.norm(l_wr - r_wr) - rel_dist = dist / shoulder_width - if rel_dist < 1.5: - return 'dome' + # ---- ДОМИК ---- + # 1. Запястья выше носа + wrists_above_nose = (l_wr[1] < nose[1] and r_wr[1] < nose[1]) + + # 2. Локти выше плеч (верхняя граница плеч – min по Y среди плеч) + shoulders_top_y = min(l_sh[1], r_sh[1]) + elbows_above_shoulders = (l_el[1] < shoulders_top_y and r_el[1] < shoulders_top_y) + + # 3. Расстояние между локтями > расстояние между плечами + elbow_distance = np.linalg.norm(l_el - r_el) + elbows_far_apart = elbow_distance > shoulder_width + + # 4. Расстояние между запястьями < половины ширины плеч + wrist_distance = np.linalg.norm(l_wr - r_wr) + wrists_near = wrist_distance < 0.5 * shoulder_width + + dome = wrists_above_nose and elbows_above_shoulders and elbows_far_apart and wrists_near + if dome: + return 'dome' return 'none'