Pose Estimation Magic: Create Fitness and Sports Analysis Apps with MediaPipe Pose

Pose Estimation Magic: Create Fitness and Sports Analysis Apps with MediaPipe Pose

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!

Written by:

343 Posts

View All Posts
Follow Me :