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: 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, }