Spaces:
Running
Running
import cv2 | |
import numpy as np | |
from pose_estimation.angle_calculation import calculate_angle | |
from voice_feedback.feedback import provide_hammer_curl_feedback , speak | |
class HammerCurl: | |
def __init__(self): | |
self.counter_right = 0 | |
self.counter_left = 0 | |
self.stage_right = None # 'up' or 'down' for right arm | |
self.stage_left = None # 'up' or 'down' for left arm | |
self.angle_threshold = 40 # Angle threshold for misalignment | |
self.flexion_angle_up = 155 # Flexion angle for 'up' stage | |
self.flexion_angle_down = 35 # Flexion angle for 'down' stage | |
self.angle_threshold_up = 155 # Upper threshold for 'up' stage | |
self.angle_threshold_down = 47 # Lower threshold for 'down' stage | |
def calculate_shoulder_elbow_hip_angle(self, shoulder, elbow, hip): | |
"""Calculate the angle between shoulder, elbow, and hip.""" | |
return calculate_angle(elbow, shoulder, hip) | |
def calculate_shoulder_elbow_wrist(self, shoulder, elbow, wrist): | |
"""Calculate the angle between shoulder, elbow, and wrist.""" | |
return calculate_angle(shoulder, elbow, wrist) | |
def track_hammer_curl(self, landmarks, frame): | |
# Right arm landmarks (shoulder, elbow, hip, wrist) | |
shoulder_right = [int(landmarks[11].x * frame.shape[1]), int(landmarks[11].y * frame.shape[0])] | |
elbow_right = [int(landmarks[13].x * frame.shape[1]), int(landmarks[13].y * frame.shape[0])] | |
hip_right = [int(landmarks[23].x * frame.shape[1]), int(landmarks[23].y * frame.shape[0])] | |
wrist_right = [int(landmarks[15].x * frame.shape[1]), int(landmarks[15].y * frame.shape[0])] | |
# Left arm landmarks (shoulder, elbow, hip, wrist) | |
shoulder_left = [int(landmarks[12].x * frame.shape[1]), int(landmarks[12].y * frame.shape[0])] | |
elbow_left = [int(landmarks[14].x * frame.shape[1]), int(landmarks[14].y * frame.shape[0])] | |
hip_left = [int(landmarks[24].x * frame.shape[1]), int(landmarks[24].y * frame.shape[0])] | |
wrist_left = [int(landmarks[16].x * frame.shape[1]), int(landmarks[16].y * frame.shape[0])] | |
# Calculate the angle for counting (elbow flexion angle) | |
angle_right_counter = self.calculate_shoulder_elbow_wrist(shoulder_right, elbow_right, wrist_right) | |
angle_left_counter = self.calculate_shoulder_elbow_wrist(shoulder_left, elbow_left, wrist_left) | |
# Calculate the angle for the right arm (shoulder, elbow, hip) | |
angle_right = self.calculate_shoulder_elbow_hip_angle(shoulder_right, elbow_right, hip_right) | |
# Calculate the angle for the left arm (shoulder, elbow, hip) | |
angle_left = self.calculate_shoulder_elbow_hip_angle(shoulder_left, elbow_left, hip_left) | |
# Draw lines with improved style | |
self.draw_line_with_style(frame, shoulder_left, elbow_left, (0, 0, 255), 4) | |
self.draw_line_with_style(frame, elbow_left, wrist_left, (0, 0, 255), 4) | |
self.draw_line_with_style(frame, shoulder_right, elbow_right, (0, 0, 255), 4) | |
self.draw_line_with_style(frame, elbow_right, wrist_right, (0, 0, 255), 4) | |
# Add circles to highlight key points | |
self.draw_circle(frame, shoulder_left, (0, 0, 255), 8) | |
self.draw_circle(frame, elbow_left, (0, 0, 255), 8) | |
self.draw_circle(frame, wrist_left, (0, 0, 255), 8) | |
self.draw_circle(frame, shoulder_right, (0, 0, 255), 8) | |
self.draw_circle(frame, elbow_right, (0, 0, 255), 8) | |
self.draw_circle(frame, wrist_right, (0, 0, 255), 8) | |
# Convert the angles to integers and update the text positions | |
angle_text_position_left = (elbow_left[0] + 10, elbow_left[1] - 10) | |
cv2.putText(frame, f'Angle: {int(angle_left_counter)}', angle_text_position_left, cv2.FONT_HERSHEY_SIMPLEX, 0.5, | |
(255, 255, 255), 2) | |
angle_text_position_right = (elbow_right[0] + 10, elbow_right[1] - 10) | |
cv2.putText(frame, f'Angle: {int(angle_right_counter)}', angle_text_position_right, cv2.FONT_HERSHEY_SIMPLEX, | |
0.5, | |
(255, 255, 255), 2) | |
warning_message_right = None | |
warning_message_left = None | |
# Check for misalignment based on shoulder-elbow-hip angle | |
if abs(angle_right) > self.angle_threshold: | |
warning_message_right = f"Right Shoulder-Elbow-Hip Misalignment! Angle: {angle_right:.2f}°" | |
if abs(angle_left) > self.angle_threshold: | |
warning_message_left = f"Left Shoulder-Elbow-Hip Misalignment! Angle: {angle_left:.2f}°" | |
if angle_right_counter > self.angle_threshold_up: | |
self.stage_right = "Flex" | |
elif self.angle_threshold_down < angle_right_counter < self.angle_threshold_up and self.stage_right == "Flex": | |
self.stage_right = "Up" | |
elif angle_right_counter < self.angle_threshold_down and self.stage_right=="Up": | |
self.stage_right = "Down" | |
self.counter_right +=1 | |
if angle_left_counter > self.angle_threshold_up: | |
self.stage_left = "Flex" | |
elif self.angle_threshold_down < angle_left_counter < self.angle_threshold_up and self.stage_left == "Flex": | |
self.stage_left = "Up" | |
elif angle_left_counter < self.angle_threshold_down and self.stage_left == "Up": | |
self.stage_left = "Down" | |
self.counter_left +=1 | |
# Progress percentages: 1 for "up", 0 for "down" | |
progress_right = 1 if self.stage_right == "up" else 0 # Note: your stage names are 'Flex', 'Up', 'Down' | |
progress_left = 1 if self.stage_left == "up" else 0 # This logic might need adjusting based on stage names | |
return self.counter_right, angle_right_counter, self.counter_left, angle_left_counter, warning_message_right, warning_message_left, progress_right, progress_left, self.stage_right, self.stage_left | |
def draw_line_with_style(self, frame, start_point, end_point, color, thickness): | |
cv2.line(frame, start_point, end_point, color, thickness, lineType=cv2.LINE_AA) | |
def draw_circle(self, frame, center, color, radius): | |
"""Draw a circle with specified style.""" | |
cv2.circle(frame, center, radius, color, -1) # -1 to fill the circle | |
# Inside the HammerCurl class in hammer_curl.py | |
def reset_reps(self): | |
self.counter_right = 0 | |
self.counter_left = 0 | |
self.stage_right = None # Or your desired initial stage, e.g., "Down" or "Flex" | |
self.stage_left = None # Or your desired initial stage | |
print("HammerCurl reps and stages reset for new set.") |