akarsh999 commited on
Commit
73bd548
·
verified ·
1 Parent(s): 814e4ee

Upload 9 files

Browse files
Files changed (1) hide show
  1. athletic_performance.py +120 -47
athletic_performance.py CHANGED
@@ -182,52 +182,126 @@ def draw_pose_landmarks(frame, landmarks, knee_analysis=None):
182
  return frame
183
 
184
 
185
- def draw_jump_reference_lines(frame, references, current_jump_height, user_height_cm):
186
- """Draw average and professional jump height reference lines."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  h, w, _ = frame.shape
188
 
189
- # Calculate line positions (relative to frame height)
190
- # Assume the person's height spans about 70% of frame height
191
- person_height_pixels = int(h * 0.7)
192
- pixels_per_cm = person_height_pixels / user_height_cm
193
-
194
- # Base line (ground level) - bottom 10% of frame
195
- ground_y = int(h * 0.9)
196
-
197
- # Reference lines
198
- avg_jump_pixels = int(references["average"] * pixels_per_cm)
199
- pro_jump_pixels = int(references["professional"] * pixels_per_cm)
200
- current_jump_pixels = int(current_jump_height * pixels_per_cm)
201
-
202
- avg_line_y = ground_y - avg_jump_pixels
203
- pro_line_y = ground_y - pro_jump_pixels
204
- current_line_y = ground_y - current_jump_pixels
205
-
206
- # Draw ground line
207
- cv2.line(frame, (0, ground_y), (w, ground_y), (100, 100, 100), 2)
208
- cv2.putText(frame, "Ground", (10, ground_y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (100, 100, 100), 2)
209
-
210
- # Draw average line
211
- if avg_line_y > 0:
212
- cv2.line(frame, (0, avg_line_y), (w, avg_line_y), (255, 255, 0), 2)
213
- cv2.putText(frame, f"Avg: {references['average']:.0f}cm",
214
- (10, avg_line_y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 0), 2)
215
-
216
- # Draw professional line
217
- if pro_line_y > 0:
218
- cv2.line(frame, (0, pro_line_y), (w, pro_line_y), (0, 255, 0), 2)
219
- cv2.putText(frame, f"Pro: {references['professional']:.0f}cm",
220
- (10, pro_line_y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
221
-
222
- # Draw current jump line
223
- if current_line_y > 0 and current_jump_height > 0:
224
- cv2.line(frame, (0, current_line_y), (w, current_line_y), (0, 0, 255), 3)
225
- cv2.putText(frame, f"Your Jump: {current_jump_height:.0f}cm",
226
- (w - 200, current_line_y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
 
 
 
 
 
 
 
 
 
 
227
 
228
  return frame
229
 
230
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  def calculate_peak_power_output(jump_height_m, body_mass_kg, flight_time_s):
232
  """Calculate peak power output using biomechanical models."""
233
  if jump_height_m <= 0 or flight_time_s <= 0:
@@ -481,19 +555,18 @@ def generate_annotated_video(video_path, user_height_cm, user_weight_kg, gender,
481
  # Draw pose landmarks with strain indicators
482
  annotated_frame = draw_pose_landmarks(frame, results.pose_landmarks, knee_analysis)
483
 
484
- # Draw jump reference lines
485
- annotated_frame = draw_jump_reference_lines(
486
- annotated_frame, jump_references, current_jump_height, user_height_cm
 
 
 
487
  )
488
 
489
  # Add performance info overlay
490
  info_y = 30
491
  cv2.putText(annotated_frame, f"Frame: {frame_idx}/{total_frames}",
492
  (10, info_y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
493
-
494
- if current_jump_height > 0:
495
- cv2.putText(annotated_frame, f"Current Jump: {current_jump_height:.1f}cm",
496
- (10, info_y + 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2)
497
 
498
  # Add knee strain warnings
499
  if knee_analysis["strain_detected"]:
 
182
  return frame
183
 
184
 
185
+ def draw_jump_reference_arrows(frame, references, person_landmarks, is_jumping, user_height_cm):
186
+ """
187
+ Draw reference arrows for average and professional jump heights near the person.
188
+ Only shows when the person is actively jumping.
189
+
190
+ Args:
191
+ frame: Video frame to draw on
192
+ references (dict): Jump height references {'average': float, 'professional': float}
193
+ person_landmarks: MediaPipe pose landmarks
194
+ is_jumping (bool): Whether the person is currently jumping
195
+ user_height_cm (float): User's height for scaling
196
+
197
+ Returns:
198
+ frame: Frame with reference arrows drawn
199
+ """
200
+ if not is_jumping or not person_landmarks:
201
+ return frame
202
+
203
  h, w, _ = frame.shape
204
 
205
+ # Get person's hip position (center point)
206
+ left_hip = person_landmarks.landmark[mp.solutions.pose.PoseLandmark.LEFT_HIP]
207
+ right_hip = person_landmarks.landmark[mp.solutions.pose.PoseLandmark.RIGHT_HIP]
208
+
209
+ # Calculate person center
210
+ person_x = int((left_hip.x + right_hip.x) / 2 * w)
211
+ person_y = int((left_hip.y + right_hip.y) / 2 * h)
212
+
213
+ # Calculate scaling factor (pixels per cm based on person height in frame)
214
+ head = person_landmarks.landmark[mp.solutions.pose.PoseLandmark.NOSE]
215
+ left_ankle = person_landmarks.landmark[mp.solutions.pose.PoseLandmark.LEFT_ANKLE]
216
+ right_ankle = person_landmarks.landmark[mp.solutions.pose.PoseLandmark.RIGHT_ANKLE]
217
+
218
+ # Person height in frame (head to ankle)
219
+ ankle_y = (left_ankle.y + right_ankle.y) / 2
220
+ person_height_pixels = abs(ankle_y - head.y) * h
221
+ pixels_per_cm = person_height_pixels / user_height_cm if user_height_cm > 0 else 1
222
+
223
+ # Ground reference (ankle level)
224
+ ground_y = int(ankle_y * h)
225
+
226
+ # Calculate reference positions
227
+ avg_height = references.get('average', 0)
228
+ pro_height = references.get('professional', 0)
229
+
230
+ # Position arrows to the right side of the person
231
+ arrow_x_start = person_x + 60
232
+ arrow_x_end = person_x + 120
233
+
234
+ # Draw average performance arrow
235
+ if avg_height > 0:
236
+ avg_y = int(ground_y - (avg_height * pixels_per_cm))
237
+ if 20 < avg_y < h - 20: # Only draw if within frame
238
+ # Draw arrow pointing to average height
239
+ cv2.arrowedLine(frame, (arrow_x_start, avg_y), (arrow_x_end, avg_y),
240
+ (255, 255, 0), 4, tipLength=0.3) # Yellow arrow
241
+ cv2.putText(frame, f"Avg: {avg_height:.0f}cm", (arrow_x_end + 10, avg_y + 5),
242
+ cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 0), 2)
243
+
244
+ # Draw professional performance arrow
245
+ if pro_height > 0:
246
+ pro_y = int(ground_y - (pro_height * pixels_per_cm))
247
+ if 20 < pro_y < h - 20: # Only draw if within frame
248
+ # Draw arrow pointing to professional height
249
+ cv2.arrowedLine(frame, (arrow_x_start, pro_y), (arrow_x_end, pro_y),
250
+ (0, 255, 0), 4, tipLength=0.3) # Green arrow
251
+ cv2.putText(frame, f"Pro: {pro_height:.0f}cm", (arrow_x_end + 10, pro_y + 5),
252
+ cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
253
 
254
  return frame
255
 
256
 
257
+ def detect_jumping_phase(landmarks, frame_height):
258
+ """
259
+ Detect if the person is currently in a jumping phase based on pose.
260
+
261
+ Args:
262
+ landmarks: MediaPipe pose landmarks
263
+ frame_height (int): Height of the video frame
264
+
265
+ Returns:
266
+ bool: True if person appears to be jumping
267
+ """
268
+ if not landmarks:
269
+ return False
270
+
271
+ try:
272
+ # Get key landmarks
273
+ left_ankle = landmarks.landmark[mp.solutions.pose.PoseLandmark.LEFT_ANKLE]
274
+ right_ankle = landmarks.landmark[mp.solutions.pose.PoseLandmark.RIGHT_ANKLE]
275
+ left_knee = landmarks.landmark[mp.solutions.pose.PoseLandmark.LEFT_KNEE]
276
+ right_knee = landmarks.landmark[mp.solutions.pose.PoseLandmark.RIGHT_KNEE]
277
+ left_hip = landmarks.landmark[mp.solutions.pose.PoseLandmark.LEFT_HIP]
278
+ right_hip = landmarks.landmark[mp.solutions.pose.PoseLandmark.RIGHT_HIP]
279
+
280
+ # Calculate average positions
281
+ ankle_y = (left_ankle.y + right_ankle.y) / 2
282
+ knee_y = (left_knee.y + right_knee.y) / 2
283
+ hip_y = (left_hip.y + right_hip.y) / 2
284
+
285
+ # Check if person is in jumping posture
286
+ # Jumping indicators:
287
+ # 1. Knees are significantly bent (knee-hip distance is small)
288
+ # 2. Person is in takeoff/landing phase (dynamic posture)
289
+
290
+ knee_hip_distance = abs(knee_y - hip_y) * frame_height
291
+ ankle_knee_distance = abs(ankle_y - knee_y) * frame_height
292
+
293
+ # If knees are bent (shorter distances) or in dynamic position, likely jumping
294
+ is_crouched = knee_hip_distance < 40 or ankle_knee_distance < 40
295
+
296
+ # Additional check: if ankles are not at the bottom of frame, person might be airborne
297
+ is_airborne = ankle_y < 0.85 # If ankles are not in bottom 15% of frame
298
+
299
+ return is_crouched or is_airborne
300
+
301
+ except (AttributeError, IndexError):
302
+ return False
303
+
304
+
305
  def calculate_peak_power_output(jump_height_m, body_mass_kg, flight_time_s):
306
  """Calculate peak power output using biomechanical models."""
307
  if jump_height_m <= 0 or flight_time_s <= 0:
 
555
  # Draw pose landmarks with strain indicators
556
  annotated_frame = draw_pose_landmarks(frame, results.pose_landmarks, knee_analysis)
557
 
558
+ # Detect if person is currently jumping
559
+ is_jumping = detect_jumping_phase(results.pose_landmarks, h)
560
+
561
+ # Draw jump reference arrows (only when jumping)
562
+ annotated_frame = draw_jump_reference_arrows(
563
+ annotated_frame, jump_references, results.pose_landmarks, is_jumping, user_height_cm
564
  )
565
 
566
  # Add performance info overlay
567
  info_y = 30
568
  cv2.putText(annotated_frame, f"Frame: {frame_idx}/{total_frames}",
569
  (10, info_y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
 
 
 
 
570
 
571
  # Add knee strain warnings
572
  if knee_analysis["strain_detected"]: