File size: 6,505 Bytes
d871c13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import streamlit as st
import cv2
import mediapipe as mp
import matplotlib.pyplot as plt
import numpy as np

# Define the function to calculate angle between the legs
def angle_between_the_legs(image):
    """
    Calculate the angle between the legs using MediaPipe pose estimation.

    Args:
        image: Input image in BGR format.

    Returns:
        A tuple containing:
        - The annotated image with visualization
        - Left leg angle (degrees)
        - Right leg angle (degrees)
        - Angle between legs (degrees)
    """
    # Initialize MediaPipe Pose
    mp_pose = mp.solutions.pose
    mp_drawing = mp.solutions.drawing_utils

    # Convert the image to RGB (MediaPipe requires RGB images)
    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

    # Initialize the Pose model
    with mp_pose.Pose(static_image_mode=True, model_complexity=2, enable_segmentation=False) as pose:
        # Process the image
        results = pose.process(image_rgb)

        # Check if pose landmarks were detected
        if not results.pose_landmarks:
            print("No pose landmarks detected.")
            return image, None, None, None

        # Create a copy of the image for annotation
        annotated_image = image.copy()

        # Get landmark coordinates
        landmarks = results.pose_landmarks.landmark

        # Get relevant landmarks for angle calculation
        # Center hip point (mid-point between left and right hip)
        mid_hip_x = (landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].x +
                     landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value].x) / 2
        mid_hip_y = (landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].y +
                     landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value].y) / 2

        # Get image dimensions for converting normalized coordinates
        h, w, _ = annotated_image.shape
        mid_hip = (int(mid_hip_x * w), int(mid_hip_y * h))

        # Get coordinates for left and right ankles
        left_ankle = (int(landmarks[mp_pose.PoseLandmark.LEFT_ANKLE.value].x * w),
                      int(landmarks[mp_pose.PoseLandmark.LEFT_ANKLE.value].y * h))

        right_ankle = (int(landmarks[mp_pose.PoseLandmark.RIGHT_ANKLE.value].x * w),
                       int(landmarks[mp_pose.PoseLandmark.RIGHT_ANKLE.value].y * h))

        # Draw the center vertical line from mid-hip down
        center_bottom = (mid_hip[0], h)
        cv2.line(annotated_image, mid_hip, center_bottom, (0, 255, 255), 2)

        # Draw lines from mid-hip to each ankle
        cv2.line(annotated_image, mid_hip, left_ankle, (255, 0, 0), 2)  # Blue line to left ankle
        cv2.line(annotated_image, mid_hip, right_ankle, (0, 0, 255), 2)  # Red line to right ankle

        # Calculate vectors
        # Vector for center line (pointing down)
        center_vector = np.array([0, 1])  # Vertical down

        # Vector for left leg
        left_leg_vector = np.array([left_ankle[0] - mid_hip[0], left_ankle[1] - mid_hip[1]])
        if np.linalg.norm(left_leg_vector) > 0:
            left_leg_vector = left_leg_vector / np.linalg.norm(left_leg_vector)

        # Vector for right leg
        right_leg_vector = np.array([right_ankle[0] - mid_hip[0], right_ankle[1] - mid_hip[1]])
        if np.linalg.norm(right_leg_vector) > 0:
            right_leg_vector = right_leg_vector / np.linalg.norm(right_leg_vector)

        # Calculate angles using dot product: angle = arccos(dot(v1, v2))
        # Note: We're using the normalized vectors for angle calculation
        left_angle_rad = np.arccos(np.clip(np.dot(center_vector, left_leg_vector), -1.0, 1.0))
        right_angle_rad = np.arccos(np.clip(np.dot(center_vector, right_leg_vector), -1.0, 1.0))

        # Convert to degrees
        left_angle_deg = np.degrees(left_angle_rad)
        right_angle_deg = np.degrees(right_angle_rad)

        # If left ankle is to the left of center, the angle is negative
        if left_ankle[0] < mid_hip[0]:
            left_angle_deg = -left_angle_deg

        # If right ankle is to the right of center, the angle is positive
        if right_ankle[0] > mid_hip[0]:
            right_angle_deg = right_angle_deg
        else:
            right_angle_deg = -right_angle_deg

        # Calculate the total angle between legs
        angle_between_legs = 2 * (abs(left_angle_deg) + abs(right_angle_deg))

        # Add text annotations with angle values
        cv2.putText(annotated_image, f"Left angle: {left_angle_deg:.1f}°",
                    (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
        cv2.putText(annotated_image, f"Right angle: {right_angle_deg:.1f}°",
                    (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
        cv2.putText(annotated_image, f"Total angle: {angle_between_legs:.1f}°",
                    (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)

        # Add marker for center hip point
        cv2.circle(annotated_image, mid_hip, 5, (255, 255, 0), -1)

        # Draw pose landmarks on the image
        mp_drawing.draw_landmarks(
            annotated_image,
            results.pose_landmarks,
            mp_pose.POSE_CONNECTIONS,
            landmark_drawing_spec=mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2, circle_radius=2),
            connection_drawing_spec=mp_drawing.DrawingSpec(color=(255, 0, 0), thickness=2))

        # Convert the annotated image back to RGB for display
        annotated_image_rgb = cv2.cvtColor(annotated_image, cv2.COLOR_BGR2RGB)

        return annotated_image_rgb, left_angle_deg, right_angle_deg, angle_between_legs


# Streamlit app
st.title("Leg Angle Calculation using MediaPipe")

# Image uploader
uploaded_file = st.file_uploader("Upload an Image", type=["png", "jpg", "jpeg"])

if uploaded_file is not None:
    # Read the image from the uploaded file
    image = np.array(bytearray(uploaded_file.read()), dtype=np.uint8)
    image = cv2.imdecode(image, cv2.IMREAD_COLOR)

    # Get the leg angle analysis
    annotated_image_rgb, left_angle, right_angle, total_angle = angle_between_the_legs(image)

    if annotated_image_rgb is not None:
        # Display the annotated image
        st.image(annotated_image_rgb, caption=f"Leg Angle Analysis: Total = {total_angle:.1f}°", use_column_width=True)

        # Print the results
        st.write(f"Left leg angle: {left_angle:.1f}°")
        st.write(f"Right leg angle: {right_angle:.1f}°")
        st.write(f"Total angle between legs: {total_angle:.1f}°")