import mediapipe as mp import time from pose_estimation.angle_calculation import calculate_angle class PushUp: def __init__(self): self.counter = 0 self.stage = "up" # Changed from "Initial" self.angle_threshold_up = 150 self.angle_threshold_down = 70 self.last_counter_update = time.time() self.mp_pose = mp.solutions.pose # Added def calculate_shoulder_elbow_wrist_angle(self, shoulder, elbow, wrist): """Calculate the angle between shoulder, elbow, and wrist.""" return calculate_angle(shoulder, elbow, wrist) def track_push_up(self, landmarks_mp, frame_width, frame_height): lm = landmarks_mp # shortcut # Left side landmarks shoulder_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value].x * frame_width), int(lm[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value].y * frame_height)] elbow_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_ELBOW.value].x * frame_width), int(lm[self.mp_pose.PoseLandmark.LEFT_ELBOW.value].y * frame_height)] wrist_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_WRIST.value].x * frame_width), int(lm[self.mp_pose.PoseLandmark.LEFT_WRIST.value].y * frame_height)] # Right side landmarks shoulder_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value].x * frame_width), int(lm[self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value].y * frame_height)] elbow_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_ELBOW.value].x * frame_width), int(lm[self.mp_pose.PoseLandmark.RIGHT_ELBOW.value].y * frame_height)] wrist_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_WRIST.value].x * frame_width), int(lm[self.mp_pose.PoseLandmark.RIGHT_WRIST.value].y * frame_height)] # Calculate angles angle_left = self.calculate_shoulder_elbow_wrist_angle(shoulder_left, elbow_left, wrist_left) angle_right = self.calculate_shoulder_elbow_wrist_angle(shoulder_right, elbow_right, wrist_right) # Stage and Counter Logic current_angle_for_logic = angle_left current_time = time.time() if current_angle_for_logic > self.angle_threshold_up: self.stage = "up" elif self.angle_threshold_down < current_angle_for_logic < self.angle_threshold_up and self.stage == "up": self.stage = "down" elif current_angle_for_logic < self.angle_threshold_down and self.stage == "down": if current_time - self.last_counter_update > 1: # 1 second debounce self.counter += 1 self.last_counter_update = current_time self.stage = "up" # Transition back to up feedback = self._get_push_up_feedback(angle_left, angle_right, self.stage) return { "counter": self.counter, "stage": self.stage, "angle_left": angle_left, "angle_right": angle_right, "feedback": feedback } def _get_push_up_feedback(self, angle_left, angle_right, stage): feedback = "Keep going!" # Default if stage == "down": if min(angle_left, angle_right) < self.angle_threshold_down - 5: feedback = "Good depth!" elif min(angle_left, angle_right) > self.angle_threshold_down + 10: feedback = "Go lower." elif stage == "up": feedback = "Push up!" # Or "Ready" if abs(angle_left - angle_right) > 25: feedback += " Try to keep your push-up even." if feedback != "Keep going!" else "Try to keep your push-up even." return feedback.strip() def get_drawing_annotations(self, landmarks_mp, frame_width, frame_height, exercise_data_dict): annotations = [] lm = landmarks_mp # shortcut # Pixel coordinates shoulder_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value].x * frame_width), int(lm[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value].y * frame_height)] elbow_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_ELBOW.value].x * frame_width), int(lm[self.mp_pose.PoseLandmark.LEFT_ELBOW.value].y * frame_height)] wrist_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_WRIST.value].x * frame_width), int(lm[self.mp_pose.PoseLandmark.LEFT_WRIST.value].y * frame_height)] shoulder_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value].x * frame_width), int(lm[self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value].y * frame_height)] elbow_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_ELBOW.value].x * frame_width), int(lm[self.mp_pose.PoseLandmark.RIGHT_ELBOW.value].y * frame_height)] wrist_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_WRIST.value].x * frame_width), int(lm[self.mp_pose.PoseLandmark.RIGHT_WRIST.value].y * frame_height)] # Lines (original colors: left (0,0,255) -> BGR [255,0,0], right (102,0,0) -> BGR [0,0,102]) annotations.append({"type": "line", "start_point": shoulder_left, "end_point": elbow_left, "color_bgr": [255, 0, 0], "thickness": 2}) annotations.append({"type": "line", "start_point": elbow_left, "end_point": wrist_left, "color_bgr": [255, 0, 0], "thickness": 2}) annotations.append({"type": "line", "start_point": shoulder_right, "end_point": elbow_right, "color_bgr": [0, 0, 102], "thickness": 2}) annotations.append({"type": "line", "start_point": elbow_right, "end_point": wrist_right, "color_bgr": [0, 0, 102], "thickness": 2}) # Circles annotations.append({"type": "circle", "center_point": shoulder_left, "radius": 8, "color_bgr": [255, 0, 0], "filled": True}) annotations.append({"type": "circle", "center_point": elbow_left, "radius": 8, "color_bgr": [255, 0, 0], "filled": True}) annotations.append({"type": "circle", "center_point": wrist_left, "radius": 8, "color_bgr": [255, 0, 0], "filled": True}) annotations.append({"type": "circle", "center_point": shoulder_right, "radius": 8, "color_bgr": [0, 0, 102], "filled": True}) annotations.append({"type": "circle", "center_point": elbow_right, "radius": 8, "color_bgr": [0, 0, 102], "filled": True}) annotations.append({"type": "circle", "center_point": wrist_right, "radius": 8, "color_bgr": [0, 0, 102], "filled": True}) # Text for angles if 'angle_left' in exercise_data_dict: annotations.append({"type": "text", "text_content": f"Angle L: {int(exercise_data_dict['angle_left'])}", "position": [elbow_left[0] + 10, elbow_left[1] - 10], "font_scale": 0.5, "color_bgr": [255, 255, 255], "thickness": 2}) if 'angle_right' in exercise_data_dict: annotations.append({"type": "text", "text_content": f"Angle R: {int(exercise_data_dict['angle_right'])}", "position": [elbow_right[0] + 10, elbow_right[1] - 10], "font_scale": 0.5, "color_bgr": [255, 255, 255], "thickness": 2}) # Display main feedback from exercise_data_dict if 'feedback' in exercise_data_dict: annotations.append({"type": "text", "text_content": exercise_data_dict['feedback'], "position": [frame_width // 2 - 150, frame_height - 40], # Adjusted for longer text "font_scale": 0.7, "color_bgr": [0, 255, 0], "thickness": 2}) # Green for feedback return annotations # Inside the PushUp class in push_up.py def reset_reps(self): self.counter = 0 self.stage = "up" # Reset to the initial stage self.last_counter_update = time.time() # Important to reset debounce timer print("PushUp reps and stage reset for new set.")