pjxcharya commited on
Commit
3908140
·
verified ·
1 Parent(s): 68be254

Update exercises/hammer_curl.py

Browse files
Files changed (1) hide show
  1. exercises/hammer_curl.py +155 -100
exercises/hammer_curl.py CHANGED
@@ -1,114 +1,169 @@
1
- import cv2
2
- import numpy as np
3
  from pose_estimation.angle_calculation import calculate_angle
4
- from voice_feedback.feedback import provide_hammer_curl_feedback , speak
5
-
6
 
7
  class HammerCurl:
8
  def __init__(self):
9
  self.counter_right = 0
10
  self.counter_left = 0
11
- self.stage_right = None # 'up' or 'down' for right arm
12
- self.stage_left = None # 'up' or 'down' for left arm
13
-
14
- self.angle_threshold = 40 # Angle threshold for misalignment
15
- self.flexion_angle_up = 155 # Flexion angle for 'up' stage
16
- self.flexion_angle_down = 35 # Flexion angle for 'down' stage
17
 
18
- self.angle_threshold_up = 155 # Upper threshold for 'up' stage
19
- self.angle_threshold_down = 47 # Lower threshold for 'down' stage
 
20
 
21
  def calculate_shoulder_elbow_hip_angle(self, shoulder, elbow, hip):
22
- """Calculate the angle between shoulder, elbow, and hip."""
 
23
  return calculate_angle(elbow, shoulder, hip)
24
 
25
  def calculate_shoulder_elbow_wrist(self, shoulder, elbow, wrist):
26
- """Calculate the angle between shoulder, elbow, and wrist."""
 
27
  return calculate_angle(shoulder, elbow, wrist)
28
 
29
- def track_hammer_curl(self, landmarks, frame):
30
- # Right arm landmarks (shoulder, elbow, hip, wrist)
31
- shoulder_right = [int(landmarks[11].x * frame.shape[1]), int(landmarks[11].y * frame.shape[0])]
32
- elbow_right = [int(landmarks[13].x * frame.shape[1]), int(landmarks[13].y * frame.shape[0])]
33
- hip_right = [int(landmarks[23].x * frame.shape[1]), int(landmarks[23].y * frame.shape[0])]
34
- wrist_right = [int(landmarks[15].x * frame.shape[1]), int(landmarks[15].y * frame.shape[0])]
35
-
36
- # Left arm landmarks (shoulder, elbow, hip, wrist)
37
- shoulder_left = [int(landmarks[12].x * frame.shape[1]), int(landmarks[12].y * frame.shape[0])]
38
- elbow_left = [int(landmarks[14].x * frame.shape[1]), int(landmarks[14].y * frame.shape[0])]
39
- hip_left = [int(landmarks[24].x * frame.shape[1]), int(landmarks[24].y * frame.shape[0])]
40
- wrist_left = [int(landmarks[16].x * frame.shape[1]), int(landmarks[16].y * frame.shape[0])]
41
-
42
- # Calculate the angle for counting (elbow flexion angle)
43
- angle_right_counter = self.calculate_shoulder_elbow_wrist(shoulder_right, elbow_right, wrist_right)
44
- angle_left_counter = self.calculate_shoulder_elbow_wrist(shoulder_left, elbow_left, wrist_left)
45
-
46
- # Calculate the angle for the right arm (shoulder, elbow, hip)
47
- angle_right = self.calculate_shoulder_elbow_hip_angle(shoulder_right, elbow_right, hip_right)
48
-
49
- # Calculate the angle for the left arm (shoulder, elbow, hip)
50
- angle_left = self.calculate_shoulder_elbow_hip_angle(shoulder_left, elbow_left, hip_left)
51
-
52
- # Draw lines with improved style
53
- self.draw_line_with_style(frame, shoulder_left, elbow_left, (0, 0, 255), 4)
54
- self.draw_line_with_style(frame, elbow_left, wrist_left, (0, 0, 255), 4)
55
-
56
- self.draw_line_with_style(frame, shoulder_right, elbow_right, (0, 0, 255), 4)
57
- self.draw_line_with_style(frame, elbow_right, wrist_right, (0, 0, 255), 4)
58
-
59
- # Add circles to highlight key points
60
- self.draw_circle(frame, shoulder_left, (0, 0, 255), 8)
61
- self.draw_circle(frame, elbow_left, (0, 0, 255), 8)
62
- self.draw_circle(frame, wrist_left, (0, 0, 255), 8)
63
-
64
- self.draw_circle(frame, shoulder_right, (0, 0, 255), 8)
65
- self.draw_circle(frame, elbow_right, (0, 0, 255), 8)
66
- self.draw_circle(frame, wrist_right, (0, 0, 255), 8)
67
-
68
- # Convert the angles to integers and update the text positions
69
- angle_text_position_left = (elbow_left[0] + 10, elbow_left[1] - 10)
70
- cv2.putText(frame, f'Angle: {int(angle_left_counter)}', angle_text_position_left, cv2.FONT_HERSHEY_SIMPLEX, 0.5,
71
- (255, 255, 255), 2)
72
-
73
- angle_text_position_right = (elbow_right[0] + 10, elbow_right[1] - 10)
74
- cv2.putText(frame, f'Angle: {int(angle_right_counter)}', angle_text_position_right, cv2.FONT_HERSHEY_SIMPLEX,
75
- 0.5,
76
- (255, 255, 255), 2)
77
-
78
- warning_message_right = None
79
- warning_message_left = None
80
-
81
- # Check for misalignment based on shoulder-elbow-hip angle
82
- if abs(angle_right) > self.angle_threshold:
83
- warning_message_right = f"Right Shoulder-Elbow-Hip Misalignment! Angle: {angle_right:.2f}°"
84
- if abs(angle_left) > self.angle_threshold:
85
- warning_message_left = f"Left Shoulder-Elbow-Hip Misalignment! Angle: {angle_left:.2f}°"
86
-
87
- if angle_right_counter > self.angle_threshold_up:
88
- self.stage_right = "Flex"
89
- elif self.angle_threshold_down < angle_right_counter < self.angle_threshold_up and self.stage_right == "Flex":
90
- self.stage_right = "Up"
91
- elif angle_right_counter < self.angle_threshold_down and self.stage_right=="Up":
92
- self.stage_right = "Down"
93
- self.counter_right +=1
94
-
95
- if angle_left_counter > self.angle_threshold_up:
96
- self.stage_left = "Flex"
97
- elif self.angle_threshold_down < angle_left_counter < self.angle_threshold_up and self.stage_left == "Flex":
98
- self.stage_left = "Up"
99
- elif angle_left_counter < self.angle_threshold_down and self.stage_left == "Up":
100
- self.stage_left = "Down"
101
- self.counter_left +=1
102
-
103
- # Progress percentages: 1 for "up", 0 for "down"
104
- progress_right = 1 if self.stage_right == "up" else 0
105
- progress_left = 1 if self.stage_left == "up" else 0
106
-
107
- 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
108
-
109
- def draw_line_with_style(self, frame, start_point, end_point, color, thickness):
110
- cv2.line(frame, start_point, end_point, color, thickness, lineType=cv2.LINE_AA)
111
-
112
- def draw_circle(self, frame, center, color, radius):
113
- """Draw a circle with specified style."""
114
- cv2.circle(frame, center, radius, color, -1) # -1 to fill the circle
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import mediapipe as mp
 
2
  from pose_estimation.angle_calculation import calculate_angle
 
 
3
 
4
  class HammerCurl:
5
  def __init__(self):
6
  self.counter_right = 0
7
  self.counter_left = 0
8
+ self.stage_right = "down"
9
+ self.stage_left = "down"
10
+ self.mp_pose = mp.solutions.pose
 
 
 
11
 
12
+ self.angle_alignment_threshold = 40 # Threshold for shoulder-elbow-hip alignment
13
+ self.angle_curl_extended = 155 # Angle when arm is considered extended
14
+ self.angle_curl_flexed = 47 # Angle when arm is considered flexed
15
 
16
  def calculate_shoulder_elbow_hip_angle(self, shoulder, elbow, hip):
17
+ # Calculate the angle between elbow, shoulder, and hip (for alignment).
18
+ # elbow is the vertex.
19
  return calculate_angle(elbow, shoulder, hip)
20
 
21
  def calculate_shoulder_elbow_wrist(self, shoulder, elbow, wrist):
22
+ # Calculate the angle between shoulder, elbow, and wrist (for curl).
23
+ # elbow is the vertex.
24
  return calculate_angle(shoulder, elbow, wrist)
25
 
26
+ def track_hammer_curl(self, landmarks_mp, frame_width, frame_height):
27
+ lm = landmarks_mp # shortcut
28
+
29
+ # Right arm landmarks
30
+ shoulder_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value].x * frame_width),
31
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value].y * frame_height)]
32
+ elbow_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_ELBOW.value].x * frame_width),
33
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_ELBOW.value].y * frame_height)]
34
+ hip_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_HIP.value].x * frame_width),
35
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_HIP.value].y * frame_height)]
36
+ wrist_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_WRIST.value].x * frame_width),
37
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_WRIST.value].y * frame_height)]
38
+
39
+ # Left arm landmarks
40
+ shoulder_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value].x * frame_width),
41
+ int(lm[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value].y * frame_height)]
42
+ elbow_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_ELBOW.value].x * frame_width),
43
+ int(lm[self.mp_pose.PoseLandmark.LEFT_ELBOW.value].y * frame_height)]
44
+ hip_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_HIP.value].x * frame_width),
45
+ int(lm[self.mp_pose.PoseLandmark.LEFT_HIP.value].y * frame_height)]
46
+ wrist_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_WRIST.value].x * frame_width),
47
+ int(lm[self.mp_pose.PoseLandmark.LEFT_WRIST.value].y * frame_height)]
48
+
49
+ # Calculate curl angles
50
+ angle_right_curl = self.calculate_shoulder_elbow_wrist(shoulder_right, elbow_right, wrist_right)
51
+ angle_left_curl = self.calculate_shoulder_elbow_wrist(shoulder_left, elbow_left, wrist_left)
52
+
53
+ # Calculate alignment angles
54
+ angle_right_alignment = self.calculate_shoulder_elbow_hip_angle(shoulder_right, elbow_right, hip_right)
55
+ angle_left_alignment = self.calculate_shoulder_elbow_hip_angle(shoulder_left, elbow_left, hip_left)
56
+
57
+ # Stage and Counter Logic - Right Arm
58
+ if angle_right_curl > self.angle_curl_extended:
59
+ self.stage_right = "down"
60
+ elif angle_right_curl < self.angle_curl_flexed and self.stage_right == "down":
61
+ self.stage_right = "up"
62
+ self.counter_right += 1
63
+
64
+ # Stage and Counter Logic - Left Arm
65
+ if angle_left_curl > self.angle_curl_extended:
66
+ self.stage_left = "down"
67
+ elif angle_left_curl < self.angle_curl_flexed and self.stage_left == "down":
68
+ self.stage_left = "up"
69
+ self.counter_left += 1
70
+
71
+ feedback_data = self._get_hammer_curl_feedback(angle_left_curl, angle_right_curl,
72
+ angle_left_alignment, angle_right_alignment,
73
+ self.stage_left, self.stage_right)
74
+
75
+ return {
76
+ "counter_left": self.counter_left,
77
+ "stage_left": self.stage_left,
78
+ "angle_left_curl": angle_left_curl,
79
+ "angle_left_alignment": angle_left_alignment,
80
+ "counter_right": self.counter_right,
81
+ "stage_right": self.stage_right,
82
+ "angle_right_curl": angle_right_curl,
83
+ "angle_right_alignment": angle_right_alignment,
84
+ "feedback_left": feedback_data["left_arm"],
85
+ "feedback_right": feedback_data["right_arm"]
86
+ }
87
+
88
+ def _get_hammer_curl_feedback(self, angle_left_curl, angle_right_curl,
89
+ angle_left_alignment, angle_right_alignment,
90
+ stage_left, stage_right):
91
+ msg_l = ""
92
+ msg_r = ""
93
+
94
+ if abs(angle_left_alignment) > self.angle_alignment_threshold:
95
+ msg_l += "Keep left elbow closer to body. "
96
+ if abs(angle_right_alignment) > self.angle_alignment_threshold:
97
+ msg_r += "Keep right elbow closer to body. "
98
+
99
+ if stage_left == "up":
100
+ if not msg_l: msg_l += "Left arm flexed. "
101
+ elif stage_left == "down":
102
+ if not msg_l: msg_l += "Left arm extended. "
103
+
104
+ if stage_right == "up":
105
+ if not msg_r: msg_r += "Right arm flexed. "
106
+ elif stage_right == "down":
107
+ if not msg_r: msg_r += "Right arm extended. "
108
+
109
+ if not msg_l.strip(): # Use strip() to check if it's empty after potential spaces
110
+ msg_l = "Left: OK"
111
+ if not msg_r.strip():
112
+ msg_r = "Right: OK"
113
+
114
+ return {"left_arm": msg_l.strip(), "right_arm": msg_r.strip()}
115
+
116
+ def get_drawing_annotations(self, landmarks_mp, frame_width, frame_height, exercise_data_dict):
117
+ annotations = []
118
+ lm = landmarks_mp
119
+
120
+ shoulder_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value].x * frame_width),
121
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value].y * frame_height)]
122
+ elbow_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_ELBOW.value].x * frame_width),
123
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_ELBOW.value].y * frame_height)]
124
+ wrist_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_WRIST.value].x * frame_width),
125
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_WRIST.value].y * frame_height)]
126
+ shoulder_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value].x * frame_width),
127
+ int(lm[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value].y * frame_height)]
128
+ elbow_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_ELBOW.value].x * frame_width),
129
+ int(lm[self.mp_pose.PoseLandmark.LEFT_ELBOW.value].y * frame_height)]
130
+ wrist_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_WRIST.value].x * frame_width),
131
+ int(lm[self.mp_pose.PoseLandmark.LEFT_WRIST.value].y * frame_height)]
132
+
133
+ color_bgr = [255, 0, 0]
134
+ thickness = 4
135
+ annotations.append({"type": "line", "start_point": shoulder_left, "end_point": elbow_left, "color_bgr": color_bgr, "thickness": thickness})
136
+ annotations.append({"type": "line", "start_point": elbow_left, "end_point": wrist_left, "color_bgr": color_bgr, "thickness": thickness})
137
+ annotations.append({"type": "line", "start_point": shoulder_right, "end_point": elbow_right, "color_bgr": color_bgr, "thickness": thickness})
138
+ annotations.append({"type": "line", "start_point": elbow_right, "end_point": wrist_right, "color_bgr": color_bgr, "thickness": thickness})
139
+
140
+ radius = 8
141
+ annotations.append({"type": "circle", "center_point": shoulder_left, "radius": radius, "color_bgr": color_bgr, "filled": True})
142
+ # ... (add all other circle and text annotations as per the previous full version of get_drawing_annotations) ...
143
+ annotations.append({"type": "circle", "center_point": elbow_left, "radius": radius, "color_bgr": color_bgr, "filled": True})
144
+ annotations.append({"type": "circle", "center_point": wrist_left, "radius": radius, "color_bgr": color_bgr, "filled": True})
145
+ annotations.append({"type": "circle", "center_point": shoulder_right, "radius": radius, "color_bgr": color_bgr, "filled": True})
146
+ annotations.append({"type": "circle", "center_point": elbow_right, "radius": radius, "color_bgr": color_bgr, "filled": True})
147
+ annotations.append({"type": "circle", "center_point": wrist_right, "radius": radius, "color_bgr": color_bgr, "filled": True})
148
+
149
+ text_color_bgr = [255, 255, 255]
150
+ font_scale = 0.5
151
+ text_thickness = 2
152
+ if 'angle_left_curl' in exercise_data_dict:
153
+ annotations.append({"type": "text", "text_content": f"L Curl: {int(exercise_data_dict['angle_left_curl'])}",
154
+ "position": [elbow_left[0] + 10, elbow_left[1] - 20],
155
+ "font_scale": font_scale, "color_bgr": text_color_bgr, "thickness": text_thickness})
156
+ if 'angle_right_curl' in exercise_data_dict:
157
+ annotations.append({"type": "text", "text_content": f"R Curl: {int(exercise_data_dict['angle_right_curl'])}",
158
+ "position": [elbow_right[0] + 10, elbow_right[1] - 20],
159
+ "font_scale": font_scale, "color_bgr": text_color_bgr, "thickness": text_thickness})
160
+
161
+ if 'feedback_left' in exercise_data_dict: # Check if key exists
162
+ annotations.append({"type": "text", "text_content": f"L: {exercise_data_dict['feedback_left']}",
163
+ "position": [10, frame_height - 70 if frame_height > 100 else 30],
164
+ "font_scale": 0.6, "color_bgr": [0, 255, 0], "thickness": 2})
165
+ if 'feedback_right' in exercise_data_dict: # Check if key exists
166
+ annotations.append({"type": "text", "text_content": f"R: {exercise_data_dict['feedback_right']}",
167
+ "position": [10, frame_height - 40 if frame_height > 70 else 60],
168
+ "font_scale": 0.6, "color_bgr": [0, 255, 0], "thickness": 2})
169
+ return annotations