fixed geom gestures
This commit is contained in:
@@ -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])
|
||||
# ---- Вспомогательные функции ----
|
||||
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
|
||||
|
||||
# 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 elbow_angle(shoulder, elbow, wrist):
|
||||
"""Угол в локте (плечо-локоть-запястье)"""
|
||||
v1 = shoulder - elbow
|
||||
v2 = wrist - elbow
|
||||
return angle_between_vectors(v1, v2)
|
||||
|
||||
# 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
|
||||
# ---- Вычисляем углы ----
|
||||
l_angle = elbow_angle(l_sh, l_el, l_wr) # угол в левом локте
|
||||
r_angle = elbow_angle(r_sh, r_el, r_wr) # угол в правом локте
|
||||
|
||||
# 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)
|
||||
# ---- КРЕСТ ----
|
||||
# 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
|
||||
)
|
||||
|
||||
cross = (wrists_crossed and wrists_chest_level and elbows_chest_level and
|
||||
arms_bent and wrists_near_center)
|
||||
|
||||
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'
|
||||
|
||||
Reference in New Issue
Block a user