Human movement analysis has revolutionized fitness, sports, and healthcare industries. From personal trainers using motion analysis to correct exercise form, to professional sports teams optimizing athlete performance, pose estimation technology is transforming how we understand and improve human movement. MediaPipe’s Pose solution makes this advanced technology accessible to every developer, enabling you to build sophisticated fitness and sports analysis applications with remarkable accuracy.
Understanding MediaPipe Pose Estimation
MediaPipe Pose detects 33 key body landmarks in real-time, providing 3D coordinates for major joints and body parts. This comprehensive body tracking enables analysis of posture, movement patterns, exercise form, and athletic performance with professional-grade accuracy.
flowchart TD A[Video Input] --> B[Pose Detection] B --> C[33 Body Landmarks] C --> D[3D Coordinate Extraction] D --> E[Movement Analysis] E --> F[Application Output] G[Upper Body] --> H[Shoulders, Elbows, Wrists] G --> I[Hip Connections] J[Lower Body] --> K[Hips, Knees, Ankles] J --> L[Foot Landmarks] M[Core Tracking] --> N[Torso Alignment] M --> O[Posture Analysis] C --> G C --> J C --> M E --> P[Fitness Form Checking] E --> Q[Sports Performance] E --> R[Rehabilitation Tracking] E --> S[Posture Monitoring] style A fill:#e3f2fd style F fill:#e8f5e8 style P fill:#fff3e0 style Q fill:#fff3e0 style R fill:#fff3e0 style S fill:#fff3e0
Building a Fitness Form Checker
Let’s create a comprehensive fitness application that can analyze exercise form, count repetitions, and provide real-time feedback to help users improve their workout technique.
import cv2
import mediapipe as mp
import numpy as np
import math
class FitnessFormChecker:
def __init__(self):
self.mp_pose = mp.solutions.pose
self.mp_draw = mp.solutions.drawing_utils
self.mp_draw_styles = mp.solutions.drawing_styles
self.pose = self.mp_pose.Pose(
static_image_mode=False,
model_complexity=1,
smooth_landmarks=True,
min_detection_confidence=0.7,
min_tracking_confidence=0.5
)
# Exercise tracking variables
self.rep_count = 0
self.exercise_state = "down" # "up" or "down"
self.angle_history = []
def calculate_angle(self, point1, point2, point3):
"""Calculate angle between three points"""
# Convert to numpy arrays
a = np.array([point1.x, point1.y])
b = np.array([point2.x, point2.y])
c = np.array([point3.x, point3.y])
# Calculate angle using dot product
radians = np.arctan2(c[1] - b[1], c[0] - b[0]) - np.arctan2(a[1] - b[1], a[0] - b[0])
angle = np.abs(radians * 180.0 / np.pi)
if angle > 180.0:
angle = 360 - angle
return angle
def analyze_pushup_form(self, landmarks):
"""Analyze push-up exercise form"""
if not landmarks:
return None, "No pose detected"
# Get relevant landmarks
left_shoulder = landmarks[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value]
left_elbow = landmarks[self.mp_pose.PoseLandmark.LEFT_ELBOW.value]
left_wrist = landmarks[self.mp_pose.PoseLandmark.LEFT_WRIST.value]
left_hip = landmarks[self.mp_pose.PoseLandmark.LEFT_HIP.value]
left_knee = landmarks[self.mp_pose.PoseLandmark.LEFT_KNEE.value]
# Calculate arm angle (elbow angle)
arm_angle = self.calculate_angle(left_shoulder, left_elbow, left_wrist)
# Calculate body alignment (shoulder to knee)
body_angle = self.calculate_angle(left_shoulder, left_hip, left_knee)
# Form feedback
feedback = []
form_score = 100
# Check arm angle for proper push-up depth
if arm_angle > 120:
feedback.append("Go deeper - bend elbows more")
form_score -= 20
elif arm_angle < 45:
feedback.append("Don't go too deep")
form_score -= 10
# Check body alignment
if abs(body_angle - 180) > 20:
feedback.append("Keep body straight")
form_score -= 30
# Count repetitions
if arm_angle < 90 and self.exercise_state == "up":
self.exercise_state = "down"
elif arm_angle > 140 and self.exercise_state == "down":
self.exercise_state = "up"
self.rep_count += 1
if not feedback:
feedback.append("Perfect form!")
return {
'arm_angle': arm_angle,
'body_angle': body_angle,
'rep_count': self.rep_count,
'form_score': max(0, form_score),
'feedback': feedback
}, None
Advanced Exercise Analysis System
Let’s expand our fitness tracker to handle multiple exercises and provide comprehensive movement analysis.
class ExerciseAnalyzer(FitnessFormChecker):
def __init__(self):
super().__init__()
self.current_exercise = "pushup"
self.exercise_data = {
'pushup': {'reps': 0, 'state': 'down'},
'squat': {'reps': 0, 'state': 'up'},
'bicep_curl': {'reps': 0, 'state': 'down'}
}
def analyze_squat_form(self, landmarks):
"""Analyze squat exercise form"""
if not landmarks:
return None, "No pose detected"
# Get relevant landmarks
left_hip = landmarks[self.mp_pose.PoseLandmark.LEFT_HIP.value]
left_knee = landmarks[self.mp_pose.PoseLandmark.LEFT_KNEE.value]
left_ankle = landmarks[self.mp_pose.PoseLandmark.LEFT_ANKLE.value]
left_shoulder = landmarks[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value]
# Calculate knee angle
knee_angle = self.calculate_angle(left_hip, left_knee, left_ankle)
# Calculate torso angle
torso_angle = abs(left_shoulder.y - left_hip.y) * 100
feedback = []
form_score = 100
# Check squat depth
if knee_angle > 120:
feedback.append("Squat deeper - thighs parallel to ground")
form_score -= 20
elif knee_angle < 70:
feedback.append("Don't go too deep")
form_score -= 10
# Check torso position
if torso_angle < 10:
feedback.append("Keep chest up and back straight")
form_score -= 25
# Count repetitions
current_state = self.exercise_data['squat']['state']
if knee_angle < 100 and current_state == "up":
self.exercise_data['squat']['state'] = "down"
elif knee_angle > 130 and current_state == "down":
self.exercise_data['squat']['state'] = "up"
self.exercise_data['squat']['reps'] += 1
if not feedback:
feedback.append("Great squat form!")
return {
'knee_angle': knee_angle,
'torso_angle': torso_angle,
'rep_count': self.exercise_data['squat']['reps'],
'form_score': max(0, form_score),
'feedback': feedback
}, None
def detect_exercise_type(self, landmarks):
"""Automatically detect which exercise is being performed"""
if not landmarks:
return "unknown"
# Get key positions
left_wrist = landmarks[self.mp_pose.PoseLandmark.LEFT_WRIST.value]
right_wrist = landmarks[self.mp_pose.PoseLandmark.RIGHT_WRIST.value]
left_shoulder = landmarks[self.mp_pose.PoseLandmark.LEFT_SHOULDER.value]
left_knee = landmarks[self.mp_pose.PoseLandmark.LEFT_KNEE.value]
left_ankle = landmarks[self.mp_pose.PoseLandmark.LEFT_ANKLE.value]
# Calculate relative positions
wrist_shoulder_ratio = abs(left_wrist.y - left_shoulder.y)
knee_ankle_distance = abs(left_knee.y - left_ankle.y)
# Exercise classification logic
if wrist_shoulder_ratio < 0.1 and left_wrist.y > left_shoulder.y:
return "pushup"
elif knee_ankle_distance > 0.2:
return "squat"
elif wrist_shoulder_ratio > 0.2:
return "bicep_curl"
return "unknown"
Sports Performance Analysis
Beyond fitness applications, pose estimation can analyze athletic performance, track technique improvements, and prevent injuries in sports.
class SportsAnalyzer:
def __init__(self):
self.mp_pose = mp.solutions.pose
self.pose = self.mp_pose.Pose(
static_image_mode=False,
model_complexity=2, # Higher complexity for sports
smooth_landmarks=True,
min_detection_confidence=0.8,
min_tracking_confidence=0.7
)
self.movement_history = []
self.velocity_data = []
def analyze_running_form(self, landmarks, frame_time):
"""Analyze running technique and gait"""
if not landmarks:
return None
# Get key running landmarks
left_hip = landmarks[self.mp_pose.PoseLandmark.LEFT_HIP.value]
right_hip = landmarks[self.mp_pose.PoseLandmark.RIGHT_HIP.value]
left_knee = landmarks[self.mp_pose.PoseLandmark.LEFT_KNEE.value]
right_knee = landmarks[self.mp_pose.PoseLandmark.RIGHT_KNEE.value]
left_ankle = landmarks[self.mp_pose.PoseLandmark.LEFT_ANKLE.value]
right_ankle = landmarks[self.mp_pose.PoseLandmark.RIGHT_ANKLE.value]
# Calculate stride characteristics
hip_center_y = (left_hip.y + right_hip.y) / 2
# Detect foot strikes
left_foot_strike = self.detect_foot_strike(left_ankle, left_knee)
right_foot_strike = self.detect_foot_strike(right_ankle, right_knee)
# Calculate cadence (steps per minute)
self.movement_history.append({
'time': frame_time,
'left_strike': left_foot_strike,
'right_strike': right_foot_strike,
'hip_height': hip_center_y
})
# Keep only recent history
if len(self.movement_history) > 300: # 10 seconds at 30fps
self.movement_history.pop(0)
# Calculate running metrics
cadence = self.calculate_cadence()
ground_contact_time = self.calculate_ground_contact_time()
vertical_oscillation = self.calculate_vertical_oscillation()
return {
'cadence': cadence,
'ground_contact_time': ground_contact_time,
'vertical_oscillation': vertical_oscillation,
'left_foot_strike': left_foot_strike,
'right_foot_strike': right_foot_strike
}
def detect_foot_strike(self, ankle, knee):
"""Detect when foot strikes the ground"""
# Simple heuristic: foot strike when ankle is below knee
return ankle.y > knee.y
def calculate_cadence(self):
"""Calculate steps per minute"""
if len(self.movement_history) < 60:
return 0
recent_data = self.movement_history[-60:] # Last 2 seconds
strikes = sum(1 for data in recent_data
if data['left_strike'] or data['right_strike'])
# Convert to steps per minute
return strikes * 30 # 30fps to 60 seconds conversion
def calculate_vertical_oscillation(self):
"""Calculate vertical movement during running"""
if len(self.movement_history) < 30:
return 0
hip_heights = [data['hip_height'] for data in self.movement_history[-30:]]
return max(hip_heights) - min(hip_heights)
Complete Fitness & Sports Application
Let’s integrate everything into a comprehensive application that can handle both fitness form checking and sports performance analysis.
def main_fitness_app():
# Initialize analyzers
exercise_analyzer = ExerciseAnalyzer()
sports_analyzer = SportsAnalyzer()
# Camera setup
cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)
# Application state
mode = "fitness" # "fitness" or "sports"
current_exercise = "pushup"
print("Fitness & Sports Analyzer Controls:")
print("- Press 'f' for Fitness mode")
print("- Press 's' for Sports mode")
print("- Press '1' for Push-ups")
print("- Press '2' for Squats")
print("- Press 'r' to reset counters")
print("- Press 'q' to quit")
frame_count = 0
start_time = cv2.getTickCount()
while True:
ret, frame = cap.read()
if not ret:
break
frame = cv2.flip(frame, 1)
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Process pose
if mode == "fitness":
results = exercise_analyzer.pose.process(rgb_frame)
else:
results = sports_analyzer.pose.process(rgb_frame)
# Draw landmarks
if results.pose_landmarks:
mp.solutions.drawing_utils.draw_landmarks(
frame, results.pose_landmarks,
exercise_analyzer.mp_pose.POSE_CONNECTIONS,
mp.solutions.drawing_styles.get_default_pose_landmarks_style()
)
# Analyze movement
if results.pose_landmarks and mode == "fitness":
landmarks = results.pose_landmarks.landmark
if current_exercise == "pushup":
analysis, error = exercise_analyzer.analyze_pushup_form(landmarks)
elif current_exercise == "squat":
analysis, error = exercise_analyzer.analyze_squat_form(landmarks)
if analysis:
# Display exercise info
cv2.putText(frame, f"Exercise: {current_exercise.title()}",
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.putText(frame, f"Reps: {analysis['rep_count']}",
(10, 70), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
cv2.putText(frame, f"Form Score: {analysis['form_score']}%",
(10, 110), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
# Display feedback
y_offset = 150
for feedback in analysis['feedback'][:3]: # Show max 3 feedback items
cv2.putText(frame, feedback, (10, y_offset),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 0), 2)
y_offset += 30
elif results.pose_landmarks and mode == "sports":
landmarks = results.pose_landmarks.landmark
current_time = cv2.getTickCount()
running_analysis = sports_analyzer.analyze_running_form(landmarks, current_time)
if running_analysis:
cv2.putText(frame, "Sports Analysis - Running",
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.putText(frame, f"Cadence: {running_analysis['cadence']} SPM",
(10, 70), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2)
cv2.putText(frame, f"Vertical Osc: {running_analysis['vertical_oscillation']:.3f}",
(10, 110), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
# Display mode
mode_color = (0, 255, 0) if mode == "fitness" else (255, 0, 255)
cv2.putText(frame, f"Mode: {mode.title()}",
(frame.shape[1] - 200, 30), cv2.FONT_HERSHEY_SIMPLEX,
0.8, mode_color, 2)
cv2.imshow('Fitness & Sports Analyzer', frame)
# Handle controls
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
elif key == ord('f'):
mode = "fitness"
elif key == ord('s'):
mode = "sports"
elif key == ord('1'):
current_exercise = "pushup"
exercise_analyzer.exercise_data['pushup']['reps'] = 0
elif key == ord('2'):
current_exercise = "squat"
exercise_analyzer.exercise_data['squat']['reps'] = 0
elif key == ord('r'):
# Reset all counters
for exercise in exercise_analyzer.exercise_data:
exercise_analyzer.exercise_data[exercise]['reps'] = 0
frame_count += 1
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main_fitness_app()
Healthcare and Rehabilitation Applications
Pose estimation has significant applications in healthcare, particularly for rehabilitation tracking and posture monitoring.
Physical Therapy
- Range of motion tracking
- Exercise compliance monitoring
- Progress measurement
- Remote therapy sessions
Workplace Safety
- Posture monitoring
- Ergonomic assessments
- Injury prevention
- Movement pattern analysis
Performance Optimization Techniques
Pose estimation is computationally intensive. Here are strategies to optimize performance while maintaining accuracy:
- Model Complexity: Choose appropriate complexity level (0, 1, or 2) based on use case
- Frame Rate Management: Process every 2nd or 3rd frame for non-critical applications
- Region of Interest: Focus processing on specific body regions when possible
- Landmark Smoothing: Enable smoothing for stable tracking
- Confidence Thresholds: Adjust detection and tracking confidence for your environment
“The future of fitness is personalized, data-driven, and accessible to everyone. Pose estimation technology makes professional-grade movement analysis available in every smartphone and computer.”
Sports Science Research Institute
What’s Next: Holistic Body Analysis
You’ve now mastered pose estimation for fitness and sports applications! In our next tutorial, we’ll explore MediaPipe’s Holistic solution, which combines face, hands, and pose detection for comprehensive human analysis and advanced applications.
Ready to revolutionize fitness and sports with AI? Download our complete pose estimation toolkit with additional exercises, sports analysis algorithms, and mobile optimization guides.
This is Part 4 of our comprehensive MediaPipe series. Coming next: Holistic body analysis combining face, hands, and pose for complete human understanding. The future of human-computer interaction awaits!