Files
posefit-server/app/exercises/dead_bug/metrics.py
T

96 lines
3.3 KiB
Python

from __future__ import annotations
import cv2
import numpy as np
from app.exercises.dead_bug.types import Point
def angle(a: Point, b: Point, c: Point) -> float:
"""计算以b为顶点的三点夹角(度数)"""
ba = np.array([a.x - b.x, a.y - b.y], dtype=np.float32)
bc = np.array([c.x - b.x, c.y - b.y], dtype=np.float32)
denom = float(np.linalg.norm(ba) * np.linalg.norm(bc))
if denom == 0:
return 0.0
cos_value = float(np.dot(ba, bc) / denom)
return float(np.degrees(np.arccos(np.clip(cos_value, -1.0, 1.0))))
def distance(a: Point, b: Point) -> float:
"""计算两点之间的欧几里得距离(归一化坐标空间)"""
return float(np.hypot(a.x - b.x, a.y - b.y))
def calculate_metrics(
lm: list[Point],
*,
left_shoulder: int,
right_shoulder: int,
left_elbow: int,
right_elbow: int,
left_wrist: int,
right_wrist: int,
left_hip: int,
right_hip: int,
left_knee: int,
right_knee: int,
left_ankle: int,
right_ankle: int,
visibility_threshold: float = 0.45,
) -> dict:
"""计算四肢关节角度、伸展状态及反馈信息"""
left_elbow_angle = angle(lm[left_shoulder], lm[left_elbow], lm[left_wrist])
right_elbow_angle = angle(lm[right_shoulder], lm[right_elbow], lm[right_wrist])
left_knee_angle = angle(lm[left_hip], lm[left_knee], lm[left_ankle])
right_knee_angle = angle(lm[right_hip], lm[right_knee], lm[right_ankle])
shoulder_width = distance(lm[left_shoulder], lm[right_shoulder])
hip_width = distance(lm[left_hip], lm[right_hip])
scale = max(shoulder_width, hip_width, 0.08)
left_arm_extended = (
left_elbow_angle >= 145
and distance(lm[left_shoulder], lm[left_wrist]) >= scale * 1.15
and lm[left_wrist].y <= lm[left_shoulder].y + scale * 0.35
)
right_arm_extended = (
right_elbow_angle >= 145
and distance(lm[right_shoulder], lm[right_wrist]) >= scale * 1.15
and lm[right_wrist].y <= lm[right_shoulder].y + scale * 0.35
)
left_leg_extended = (
left_knee_angle >= 150
and distance(lm[left_hip], lm[left_ankle]) >= scale * 1.55
and lm[left_ankle].y >= lm[left_knee].y - scale * 0.2
)
right_leg_extended = (
right_knee_angle >= 150
and distance(lm[right_hip], lm[right_ankle]) >= scale * 1.55
and lm[right_ankle].y >= lm[right_knee].y - scale * 0.2
)
feedback: list[str] = []
if left_arm_extended and left_elbow_angle < 160:
feedback.append("Straighten left arm")
if right_arm_extended and right_elbow_angle < 160:
feedback.append("Straighten right arm")
if left_leg_extended and left_knee_angle < 165:
feedback.append("Straighten left leg")
if right_leg_extended and right_knee_angle < 165:
feedback.append("Straighten right leg")
return {
"left_arm_extended": left_arm_extended,
"right_arm_extended": right_arm_extended,
"left_leg_extended": left_leg_extended,
"right_leg_extended": right_leg_extended,
"left_elbow_angle": left_elbow_angle,
"right_elbow_angle": right_elbow_angle,
"left_knee_angle": left_knee_angle,
"right_knee_angle": right_knee_angle,
"scale": scale,
"feedback": feedback,
}