Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import numpy as np
|
3 |
+
import matplotlib.pyplot as plt
|
4 |
+
import mediapipe as mp
|
5 |
+
import gradio as gr
|
6 |
+
|
7 |
+
# Initialize Mediapipe Pose model
|
8 |
+
mp_pose = mp.solutions.pose
|
9 |
+
pose = mp_pose.Pose(static_image_mode=True)
|
10 |
+
|
11 |
+
# Function to estimate height using dynamic calibration based on shoulder width
|
12 |
+
def estimate_real_world_height_and_area(image):
|
13 |
+
height, width, _ = image.shape
|
14 |
+
results = pose.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
|
15 |
+
|
16 |
+
if not results.pose_landmarks:
|
17 |
+
print("No landmarks detected.")
|
18 |
+
return None, None, None # Return None if no landmarks detected
|
19 |
+
|
20 |
+
landmarks = results.pose_landmarks.landmark
|
21 |
+
|
22 |
+
# Reference average shoulder width (in cm)
|
23 |
+
AVERAGE_SHOULDER_WIDTH_CM = 45
|
24 |
+
|
25 |
+
# Points for height (nose to ankle) and shoulder width
|
26 |
+
nose = landmarks[mp_pose.PoseLandmark.NOSE]
|
27 |
+
left_shoulder = landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER]
|
28 |
+
right_shoulder = landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER]
|
29 |
+
left_ankle = landmarks[mp_pose.PoseLandmark.LEFT_ANKLE]
|
30 |
+
right_ankle = landmarks[mp_pose.PoseLandmark.RIGHT_ANKLE]
|
31 |
+
|
32 |
+
# Calculate pixel height between nose (head) and ankle
|
33 |
+
head_y = int(nose.y * height)
|
34 |
+
ankle_y = int((left_ankle.y + right_ankle.y) / 2 * height)
|
35 |
+
pixel_height = abs(ankle_y - head_y)
|
36 |
+
|
37 |
+
# Calculate shoulder width in pixels
|
38 |
+
shoulder_width_pixels = abs(left_shoulder.x - right_shoulder.x) * width
|
39 |
+
|
40 |
+
# Determine the pixel-to-cm ratio using shoulder width
|
41 |
+
pixel_to_cm_ratio = AVERAGE_SHOULDER_WIDTH_CM / shoulder_width_pixels if shoulder_width_pixels != 0 else 0
|
42 |
+
|
43 |
+
# Calculate real-world height using this ratio
|
44 |
+
real_world_height_cm = pixel_height * pixel_to_cm_ratio
|
45 |
+
|
46 |
+
# Estimate torso area in pixels
|
47 |
+
torso_width = abs(left_shoulder.x - right_shoulder.x) * width
|
48 |
+
torso_height = abs(left_shoulder.y - left_ankle.y) * height
|
49 |
+
torso_area_pixels = torso_width * torso_height
|
50 |
+
real_torso_area = torso_area_pixels * (pixel_to_cm_ratio ** 2)
|
51 |
+
|
52 |
+
return real_world_height_cm, real_torso_area, landmarks
|
53 |
+
|
54 |
+
# Main Gradio prediction function with scaling and plotting
|
55 |
+
def predict(image):
|
56 |
+
try:
|
57 |
+
# Classify Gender
|
58 |
+
gender = classify_gender(image) # Assuming this function is defined
|
59 |
+
|
60 |
+
# Estimate height and area
|
61 |
+
real_height, real_torso_area, landmarks = estimate_real_world_height_and_area(image)
|
62 |
+
|
63 |
+
if real_height is None or real_torso_area is None:
|
64 |
+
return "No landmarks detected; please use a clearer image.", None, None, None
|
65 |
+
|
66 |
+
# Plot with scale
|
67 |
+
fig, ax = plt.subplots(figsize=(10, 10))
|
68 |
+
ax.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
|
69 |
+
|
70 |
+
# Plot landmarks if they exist
|
71 |
+
if landmarks:
|
72 |
+
for landmark in landmarks:
|
73 |
+
ax.scatter(landmark.x * image.shape[1], landmark.y * image.shape[0], color="red", s=10)
|
74 |
+
|
75 |
+
# Add height and area text
|
76 |
+
ax.text(10, 30, f"Predicted Gender: {gender}", color="yellow", fontsize=12, backgroundcolor='black')
|
77 |
+
ax.text(10, 60, f"Estimated Height: {real_height:.2f} cm", color="yellow", fontsize=12, backgroundcolor='black')
|
78 |
+
ax.text(10, 90, f"Estimated Torso Area: {real_torso_area:.2f} cm^2", color="yellow", fontsize=12, backgroundcolor='black')
|
79 |
+
|
80 |
+
# Add grid scale to background
|
81 |
+
ax.set_xticks(np.arange(0, image.shape[1], 50))
|
82 |
+
ax.set_yticks(np.arange(0, image.shape[0], 50))
|
83 |
+
ax.grid(color='white', linestyle='--', linewidth=0.5)
|
84 |
+
|
85 |
+
# Save annotated plot for output
|
86 |
+
plt.savefig("output_plot.png")
|
87 |
+
plt.close(fig)
|
88 |
+
|
89 |
+
return gender, real_height, real_torso_area, "output_plot.png"
|
90 |
+
except Exception as e:
|
91 |
+
print(f"Error encountered: {e}")
|
92 |
+
return f"An error occurred: {e}", None, None, None
|
93 |
+
|
94 |
+
# Define Gradio interface
|
95 |
+
image_input = gr.Image(label="Input Image")
|
96 |
+
text_output = gr.Textbox(label="Predicted Gender")
|
97 |
+
height_output = gr.Textbox(label="Estimated Height (cm)")
|
98 |
+
area_output = gr.Textbox(label="Estimated Torso Area (cm^2)")
|
99 |
+
image_output = gr.Image(label="Annotated Image with Measurements")
|
100 |
+
|
101 |
+
# Set up Gradio interface
|
102 |
+
gr_interface = gr.Interface(
|
103 |
+
fn=predict,
|
104 |
+
inputs=image_input,
|
105 |
+
outputs=[text_output, height_output, area_output, image_output],
|
106 |
+
title="Gender, Height, and Body Measurement Estimation",
|
107 |
+
description="Upload an image to predict gender, estimate height, and calculate 2D torso area with a scale overlay."
|
108 |
+
)
|
109 |
+
|
110 |
+
# Launch the Gradio app
|
111 |
+
gr_interface.launch()
|