pjxcharya commited on
Commit
14e399f
·
verified ·
1 Parent(s): 6d537bf

Update exercises/squat.py

Browse files
Files changed (1) hide show
  1. exercises/squat.py +127 -47
exercises/squat.py CHANGED
@@ -1,62 +1,142 @@
1
- import cv2
2
  from pose_estimation.angle_calculation import calculate_angle
3
 
4
  class Squat:
5
  def __init__(self):
6
  self.counter = 0
7
- self.stage = None
 
8
 
9
- def calculate_angle(self, hip, knee, ankle):
10
- return calculate_angle(hip, knee, ankle)
11
 
12
- def track_squat(self, landmarks, frame):
13
- # Landmark coordinates
14
- hip = [int(landmarks[23].x * frame.shape[1]), int(landmarks[23].y * frame.shape[0])]
15
- knee = [int(landmarks[25].x * frame.shape[1]), int(landmarks[25].y * frame.shape[0])]
16
- shoulder = [int(landmarks[11].x * frame.shape[1]), int(landmarks[11].y * frame.shape[0])]
17
 
18
- hip_right = [int(landmarks[24].x * frame.shape[1]), int(landmarks[24].y * frame.shape[0])]
19
- knee_right = [int(landmarks[26].x * frame.shape[1]), int(landmarks[26].y * frame.shape[0])]
20
- shoulder_right = [int(landmarks[12].x * frame.shape[1]), int(landmarks[12].y * frame.shape[0])]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  # Calculate angles
23
- angle = self.calculate_angle(shoulder, hip, knee)
24
  angle_right = self.calculate_angle(shoulder_right, hip_right, knee_right)
25
 
26
- # Draw lines and circles to highlight key points
27
- self.draw_line_with_style(frame, shoulder, hip, (178, 102, 255), 2)
28
- self.draw_line_with_style(frame, hip, knee, (178, 102, 255), 2)
29
- self.draw_line_with_style(frame, shoulder_right, hip_right, (51, 153, 255), 2)
30
- self.draw_line_with_style(frame, hip_right, knee_right, (51, 153, 255), 2)
31
-
32
- self.draw_circle(frame, shoulder, (178, 102, 255), 8)
33
- self.draw_circle(frame, hip, (178, 102, 255), 8)
34
- self.draw_circle(frame, knee, (178, 102, 255), 8)
35
- self.draw_circle(frame, shoulder_right, (51, 153, 255), 8)
36
- self.draw_circle(frame, hip_right, (51, 153, 255), 8)
37
- self.draw_circle(frame, knee_right, (51, 153, 255), 8)
38
-
39
- # Display angles on screen
40
- angle_text_position = (knee[0] + 10, knee[1] - 10)
41
- cv2.putText(frame, f'Angle Left: {int(angle)}', angle_text_position, cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
42
-
43
- angle_text_position_right = (knee_right[0] + 10, knee_right[1] - 10)
44
- cv2.putText(frame, f'Angle Right: {int(angle_right)}', angle_text_position_right, cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
45
-
46
- # Update exercise stage and counter
47
- if angle > 170:
48
- self.stage = "Starting Position"
49
- elif 90 < angle < 170 and self.stage == "Starting Position":
50
- self.stage = "Descent"
51
- elif angle < 90 and self.stage == "Descent":
52
- self.stage = "Ascent"
53
  self.counter += 1
54
- return self.counter, angle, self.stage
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
- def draw_line_with_style(self, frame, start_point, end_point, color, thickness):
57
- """Draw a line with specified style."""
58
- cv2.line(frame, start_point, end_point, color, thickness, lineType=cv2.LINE_AA)
59
 
60
- def draw_circle(self, frame, center, color, radius):
61
- """Draw a circle with specified style."""
62
- 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 Squat:
5
  def __init__(self):
6
  self.counter = 0
7
+ self.stage = "up" # Initial stage
8
+ self.mp_pose = mp.solutions.pose # Added for convenience
9
 
10
+ def calculate_angle(self, point1, point2, point3): # Assuming these are pixel coordinates
11
+ return calculate_angle(point1, point2, point3)
12
 
13
+ def track_squat(self, landmarks_mp, frame_width, frame_height):
14
+ lm = landmarks_mp # shortcut
 
 
 
15
 
16
+ # Left side landmarks
17
+ shoulder_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value].x * frame_width),
18
+ int(lm[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value].y * frame_height)]
19
+ hip_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_HIP.value].x * frame_width),
20
+ int(lm[self.mp_pose.PoseLandmark.LEFT_HIP.value].y * frame_height)]
21
+ knee_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_KNEE.value].x * frame_width),
22
+ int(lm[self.mp_pose.PoseLandmark.LEFT_KNEE.value].y * frame_height)]
23
+ # ankle_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_ANKLE.value].x * frame_width),
24
+ # int(lm[self.mp_pose.PoseLandmark.LEFT_ANKLE.value].y * frame_height)]
25
+
26
+
27
+ # Right side landmarks
28
+ shoulder_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value].x * frame_width),
29
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value].y * frame_height)]
30
+ hip_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_HIP.value].x * frame_width),
31
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_HIP.value].y * frame_height)]
32
+ knee_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_KNEE.value].x * frame_width),
33
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_KNEE.value].y * frame_height)]
34
+ # ankle_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_ANKLE.value].x * frame_width),
35
+ # int(lm[self.mp_pose.PoseLandmark.RIGHT_ANKLE.value].y * frame_height)]
36
 
37
  # Calculate angles
38
+ angle_left = self.calculate_angle(shoulder_left, hip_left, knee_left)
39
  angle_right = self.calculate_angle(shoulder_right, hip_right, knee_right)
40
 
41
+ # Stage and counter logic (using angle_left for primary logic)
42
+ current_angle_for_logic = angle_left
43
+ if current_angle_for_logic > 170:
44
+ self.stage = "up"
45
+ elif 90 < current_angle_for_logic < 170 and self.stage == "up":
46
+ self.stage = "down"
47
+ elif current_angle_for_logic < 90 and self.stage == "down":
48
+ self.stage = "up"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  self.counter += 1
50
+
51
+ feedback_message = self._get_squat_feedback(angle_left, angle_right, self.stage,
52
+ knee_left, hip_left, shoulder_left,
53
+ knee_right, hip_right, shoulder_right)
54
+
55
+ return {
56
+ "counter": self.counter,
57
+ "stage": self.stage,
58
+ "angle_left": angle_left,
59
+ "angle_right": angle_right,
60
+ "feedback": feedback_message
61
+ }
62
+
63
+ def _get_squat_feedback(self, angle_left, angle_right, stage,
64
+ knee_left, hip_left, shoulder_left,
65
+ knee_right, hip_right, shoulder_right): # Added points for future use
66
+ feedback = "Keep going." # Default feedback
67
+
68
+ if stage == "down":
69
+ if min(angle_left, angle_right) < 80:
70
+ feedback = "Good depth!"
71
+ elif min(angle_left, angle_right) > 100: # Knees should be more bent
72
+ feedback = "Go lower."
73
+
74
+ if abs(angle_left - angle_right) > 20: # Check for uneven squat
75
+ # Adding a check to see if there's significant movement, e.g., not in "up" stage fully extended
76
+ if not (stage == "up" and min(angle_left, angle_right) > 160): # Avoid this message if standing straight
77
+ feedback += " Try to keep your squat even." if feedback != "Keep going." else "Try to keep your squat even."
78
+
79
+
80
+ # Placeholder for more advanced feedback using the passed points:
81
+ # E.g., Knee valgus: check if knee_left.x < hip_left.x and knee_left.x > shoulder_left.x (simplified)
82
+ # E.g., Back posture: calculate angle shoulder-hip-ankle (requires ankle points)
83
+
84
+ return feedback.strip()
85
+
86
+
87
+ def get_drawing_annotations(self, landmarks_mp, frame_width, frame_height, exercise_data_dict):
88
+ annotations = []
89
+ lm = landmarks_mp # shortcut
90
+
91
+ # Re-calculate or retrieve necessary points (pixel coordinates)
92
+ # For simplicity, re-calculating here. Could be optimized by passing from track_squat.
93
+ shoulder_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value].x * frame_width),
94
+ int(lm[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value].y * frame_height)]
95
+ hip_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_HIP.value].x * frame_width),
96
+ int(lm[self.mp_pose.PoseLandmark.LEFT_HIP.value].y * frame_height)]
97
+ knee_left = [int(lm[self.mp_pose.PoseLandmark.LEFT_KNEE.value].x * frame_width),
98
+ int(lm[self.mp_pose.PoseLandmark.LEFT_KNEE.value].y * frame_height)]
99
+
100
+ shoulder_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value].x * frame_width),
101
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value].y * frame_height)]
102
+ hip_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_HIP.value].x * frame_width),
103
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_HIP.value].y * frame_height)]
104
+ knee_right = [int(lm[self.mp_pose.PoseLandmark.RIGHT_KNEE.value].x * frame_width),
105
+ int(lm[self.mp_pose.PoseLandmark.RIGHT_KNEE.value].y * frame_height)]
106
+
107
+ # Lines for left side (original color: (178, 102, 255) -> BGR: [255, 102, 178])
108
+ annotations.append({"type": "line", "start_point": shoulder_left, "end_point": hip_left, "color_bgr": [255, 102, 178], "thickness": 2})
109
+ annotations.append({"type": "line", "start_point": hip_left, "end_point": knee_left, "color_bgr": [255, 102, 178], "thickness": 2})
110
+
111
+ # Lines for right side (original color: (51, 153, 255) -> BGR: [255, 153, 51])
112
+ annotations.append({"type": "line", "start_point": shoulder_right, "end_point": hip_right, "color_bgr": [255, 153, 51], "thickness": 2})
113
+ annotations.append({"type": "line", "start_point": hip_right, "end_point": knee_right, "color_bgr": [255, 153, 51], "thickness": 2})
114
+
115
+ # Circles for left side
116
+ annotations.append({"type": "circle", "center_point": shoulder_left, "radius": 8, "color_bgr": [255, 102, 178], "filled": True})
117
+ annotations.append({"type": "circle", "center_point": hip_left, "radius": 8, "color_bgr": [255, 102, 178], "filled": True})
118
+ annotations.append({"type": "circle", "center_point": knee_left, "radius": 8, "color_bgr": [255, 102, 178], "filled": True})
119
+
120
+ # Circles for right side
121
+ annotations.append({"type": "circle", "center_point": shoulder_right, "radius": 8, "color_bgr": [255, 153, 51], "filled": True})
122
+ annotations.append({"type": "circle", "center_point": hip_right, "radius": 8, "color_bgr": [255, 153, 51], "filled": True})
123
+ annotations.append({"type": "circle", "center_point": knee_right, "radius": 8, "color_bgr": [255, 153, 51], "filled": True})
124
+
125
+ # Text for angles
126
+ if 'angle_left' in exercise_data_dict:
127
+ annotations.append({"type": "text", "text_content": f"Angle L: {int(exercise_data_dict['angle_left'])}",
128
+ "position": [knee_left[0] + 10, knee_left[1] - 10],
129
+ "font_scale": 0.5, "color_bgr": [255, 255, 255], "thickness": 2})
130
+ if 'angle_right' in exercise_data_dict:
131
+ annotations.append({"type": "text", "text_content": f"Angle R: {int(exercise_data_dict['angle_right'])}",
132
+ "position": [knee_right[0] + 10, knee_right[1] - 10],
133
+ "font_scale": 0.5, "color_bgr": [255, 255, 255], "thickness": 2})
134
+
135
+ # Display main feedback from exercise_data_dict
136
+ if 'feedback' in exercise_data_dict:
137
+ annotations.append({"type": "text", "text_content": exercise_data_dict['feedback'],
138
+ "position": [frame_width // 2 - 100, frame_height - 40], # Centered at bottom
139
+ "font_scale": 0.7, "color_bgr": [0, 0, 255], "thickness": 2})
140
 
 
 
 
141
 
142
+ return annotations