Update app.py
Browse files
app.py
CHANGED
@@ -129,25 +129,121 @@ def angle_between_the_legs(image):
|
|
129 |
return annotated_image_rgb, left_angle_deg, right_angle_deg, angle_between_legs
|
130 |
|
131 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
# Streamlit app
|
133 |
-
st.title("
|
134 |
|
135 |
-
#
|
136 |
-
uploaded_file = st.file_uploader("Upload an
|
137 |
|
138 |
if uploaded_file is not None:
|
139 |
-
#
|
140 |
image = np.array(bytearray(uploaded_file.read()), dtype=np.uint8)
|
141 |
image = cv2.imdecode(image, cv2.IMREAD_COLOR)
|
142 |
|
143 |
-
#
|
144 |
-
|
145 |
-
|
146 |
-
if annotated_image_rgb is not None:
|
147 |
-
# Display the annotated image
|
148 |
-
st.image(annotated_image_rgb, caption=f"Leg Angle Analysis: Total = {total_angle:.1f}°", use_column_width=True)
|
149 |
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
st.write(f"Total angle between legs: {total_angle:.1f}°")
|
|
|
129 |
return annotated_image_rgb, left_angle_deg, right_angle_deg, angle_between_legs
|
130 |
|
131 |
|
132 |
+
# Define the function to calculate the tilt of the body
|
133 |
+
def tilt_of_body(image):
|
134 |
+
"""
|
135 |
+
Calculate the tilt angle of the body by measuring the angle between a vertical line (y-axis)
|
136 |
+
and a line connecting the shoulders.
|
137 |
+
|
138 |
+
Args:
|
139 |
+
image: Input image in BGR format.
|
140 |
+
|
141 |
+
Returns:
|
142 |
+
A tuple containing:
|
143 |
+
- The annotated image with visualization
|
144 |
+
- Tilt angle in degrees
|
145 |
+
"""
|
146 |
+
# Initialize MediaPipe Pose
|
147 |
+
mp_pose = mp.solutions.pose
|
148 |
+
mp_drawing = mp.solutions.drawing_utils
|
149 |
+
|
150 |
+
# Convert the image to RGB (MediaPipe requires RGB images)
|
151 |
+
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
152 |
+
|
153 |
+
# Initialize the Pose model
|
154 |
+
with mp_pose.Pose(static_image_mode=True, model_complexity=2, enable_segmentation=False) as pose:
|
155 |
+
# Process the image
|
156 |
+
results = pose.process(image_rgb)
|
157 |
+
|
158 |
+
# Check if pose landmarks were detected
|
159 |
+
if not results.pose_landmarks:
|
160 |
+
print("No pose landmarks detected.")
|
161 |
+
return image, None
|
162 |
+
|
163 |
+
# Create a copy of the image for annotation
|
164 |
+
annotated_image = image.copy()
|
165 |
+
|
166 |
+
# Get landmark coordinates
|
167 |
+
landmarks = results.pose_landmarks.landmark
|
168 |
+
|
169 |
+
# Get image dimensions for converting normalized coordinates
|
170 |
+
h, w, _ = annotated_image.shape
|
171 |
+
|
172 |
+
# Get relevant landmarks
|
173 |
+
# Left shoulder point
|
174 |
+
left_shoulder = (int(landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].x * w),
|
175 |
+
int(landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].y * h))
|
176 |
+
|
177 |
+
# Right shoulder point
|
178 |
+
right_shoulder = (int(landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value].x * w),
|
179 |
+
int(landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value].y * h))
|
180 |
+
|
181 |
+
# Draw the vertical line (y-axis) from mid-hip
|
182 |
+
vertical_top = (w // 2, 0)
|
183 |
+
vertical_bottom = (w // 2, h)
|
184 |
+
cv2.line(annotated_image, vertical_top, vertical_bottom, (0, 255, 255), 2)
|
185 |
+
|
186 |
+
# Draw the line connecting the shoulders
|
187 |
+
cv2.line(annotated_image, left_shoulder, right_shoulder, (255, 0, 0), 2)
|
188 |
+
|
189 |
+
# Calculate vectors for angle measurement
|
190 |
+
vertical_vector = np.array([0, 1]) # Vertical direction (down is positive in image coordinates)
|
191 |
+
shoulder_vector = np.array([right_shoulder[0] - left_shoulder[0],
|
192 |
+
right_shoulder[1] - left_shoulder[1]])
|
193 |
+
|
194 |
+
# Normalize shoulder vector
|
195 |
+
if np.linalg.norm(shoulder_vector) > 0:
|
196 |
+
shoulder_vector = shoulder_vector / np.linalg.norm(shoulder_vector)
|
197 |
+
|
198 |
+
# Calculate the angle between the vertical line and the shoulder line
|
199 |
+
dot_product = np.dot(vertical_vector, shoulder_vector)
|
200 |
+
cross_product = np.cross(np.array([vertical_vector[0], vertical_vector[1], 0]),
|
201 |
+
np.array([shoulder_vector[0], shoulder_vector[1], 0]))[2]
|
202 |
+
|
203 |
+
# Calculate angle using arccos
|
204 |
+
angle_rad = np.arccos(np.clip(dot_product, -1.0, 1.0))
|
205 |
+
angle_deg = np.degrees(angle_rad)
|
206 |
+
|
207 |
+
# Determine the direction of tilt
|
208 |
+
if cross_product < 0:
|
209 |
+
angle_deg = -angle_deg
|
210 |
+
|
211 |
+
# Add text annotation with tilt angle value
|
212 |
+
cv2.putText(annotated_image, f"Tilt angle: {angle_deg:.1f}°",
|
213 |
+
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
|
214 |
+
|
215 |
+
# Add markers for key points
|
216 |
+
cv2.circle(annotated_image, left_shoulder, 5, (0, 255, 0), -1) # Green for left shoulder
|
217 |
+
cv2.circle(annotated_image, right_shoulder, 5, (0, 255, 0), -1) # Green for right shoulder
|
218 |
+
|
219 |
+
# Draw pose landmarks on the image
|
220 |
+
mp_drawing.draw_landmarks(
|
221 |
+
annotated_image,
|
222 |
+
results.pose_landmarks,
|
223 |
+
mp_pose.POSE_CONNECTIONS,
|
224 |
+
landmark_drawing_spec=mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2, circle_radius=2),
|
225 |
+
connection_drawing_spec=mp_drawing.DrawingSpec(color=(255, 0, 0), thickness=2))
|
226 |
+
|
227 |
+
# Convert the annotated image back to RGB for display
|
228 |
+
annotated_image_rgb = cv2.cvtColor(annotated_image, cv2.COLOR_BGR2RGB)
|
229 |
+
|
230 |
+
return annotated_image_rgb, angle_deg
|
231 |
+
|
232 |
# Streamlit app
|
233 |
+
st.title("Body and Leg Pose Analysis")
|
234 |
|
235 |
+
# Upload image
|
236 |
+
uploaded_file = st.file_uploader("Upload an image", type=["jpg", "jpeg", "png"])
|
237 |
|
238 |
if uploaded_file is not None:
|
239 |
+
# Load the image using OpenCV
|
240 |
image = np.array(bytearray(uploaded_file.read()), dtype=np.uint8)
|
241 |
image = cv2.imdecode(image, cv2.IMREAD_COLOR)
|
242 |
|
243 |
+
# Analyze angles between legs and tilt of the body
|
244 |
+
annotated_image_legs, left_angle, right_angle, total_angle = angle_between_the_legs(image)
|
245 |
+
annotated_image_tilt, tilt_angle = tilt_of_body(image)
|
|
|
|
|
|
|
246 |
|
247 |
+
# Show the annotated images
|
248 |
+
st.image(annotated_image_legs, caption=f"Leg Angles (Total: {total_angle:.1f}°)", use_column_width=True)
|
249 |
+
st.image(annotated_image_tilt, caption=f"Body Tilt Angle: {tilt_angle:.1f}°", use_column_width=True)
|
|