BodyMeasurement / app.py
AnishaNaik03's picture
Update app.py
d974b87 verified
import torch
import numpy as np
import cv2
import json
import os
import gradio as gr
from detectron2.detectron2.engine import DefaultPredictor
from detectron2.detectron2.config import get_cfg
from detectron2 import model_zoo
import torch_utils
import dnnlib
# Create output directory if it doesn't exist
output_dir = "key/"
os.makedirs(output_dir, exist_ok=True)
output_file = os.path.join(output_dir, "keypoints.json")
# Load pre-trained Keypoint R-CNN model
cfg = get_cfg()
cfg.merge_from_file(model_zoo.get_config_file("COCO-Keypoints/keypoint_rcnn_R_50_FPN_3x.yaml"))
cfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url("COCO-Keypoints/keypoint_rcnn_R_50_FPN_3x.yaml")
cfg.MODEL.DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
# Load the predictor
predictor = DefaultPredictor(cfg)
def process_image(image, user_height_cm):
# Convert Gradio image input to OpenCV format
image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
# Run keypoint detection
outputs = predictor(image)
# Extract keypoints
instances = outputs["instances"]
keypoints = instances.pred_keypoints.cpu().numpy().tolist() if instances.has("pred_keypoints") else None
if not keypoints:
return "No keypoints detected.", None
# Save keypoints to JSON
with open(output_file, "w") as f:
json.dump({"keypoints": keypoints}, f, indent=4)
keypoints = np.array(keypoints[0])[:, :2] # Extract (x, y) coordinates
# COCO format indices
NOSE, L_SHOULDER, R_SHOULDER = 0, 5, 6
L_ELBOW, R_ELBOW = 7, 8
L_WRIST, R_WRIST = 9, 10
L_HIP, R_HIP = 11, 12
L_ANKLE, R_ANKLE = 15, 16
# Define Keypoint Pairs for Drawing Lines (COCO Format)
skeleton = [(5, 6), (5, 11), (6, 12), (11, 12)]
# Draw Keypoints
for x, y in keypoints:
cv2.circle(image, (int(x), int(y)), 5, (0, 255, 0), -1)
# Draw Skeleton
for pt1, pt2 in skeleton:
x1, y1 = map(int, keypoints[pt1])
x2, y2 = map(int, keypoints[pt2])
cv2.line(image, (x1, y1), (x2, y2), (255, 0, 0), 2)
# Function to calculate Euclidean distance
def get_distance(p1, p2):
return np.linalg.norm(np.array(p1) - np.array(p2))
# Calculate full height (consider head length)
ankle_mid = ((keypoints[L_ANKLE] + keypoints[R_ANKLE]) / 2).tolist()
pixel_height = get_distance(keypoints[NOSE], ankle_mid)
# Estimated full body height (add approx head length)
estimated_full_pixel_height = pixel_height / 0.87 # Since 87% = nose to ankle
pixels_per_cm = estimated_full_pixel_height / user_height_cm
# Waist and shoulder measurements
shoulder_width_px = get_distance(keypoints[L_SHOULDER], keypoints[R_SHOULDER])
waist_width_px = get_distance(keypoints[L_HIP], keypoints[R_HIP])
# Convert to cm
shoulder_width_cm = shoulder_width_px / pixels_per_cm
waist_width_cm = waist_width_px / pixels_per_cm
# Torso Length (Neck to Pelvis)
pelvis = ((keypoints[L_HIP] + keypoints[R_HIP]) / 2).tolist()
neck = ((keypoints[L_SHOULDER] + keypoints[R_SHOULDER]) / 2).tolist()
torso_length_px = get_distance(neck, pelvis)
torso_length_cm = torso_length_px / pixels_per_cm
# Arm Length (Shoulder to Wrist)
arm_length_px = get_distance(keypoints[L_SHOULDER], keypoints[L_WRIST])
arm_length_cm = arm_length_px / pixels_per_cm
# Calculate waist and hip circumference (Ellipse approximation)
# Waist circumference ≈ π × (waist_width / 2) × 2
waist_circumference = np.pi * waist_width_cm
hip_circumference = waist_circumference / 0.75 # Assuming hip is slightly bigger than waist
# Improved body measurement calculation
def calculate_body_measurements(waist_circumference, hip_circumference, shoulder_width_cm, torso_length_cm, arm_length_cm):
return {
"Waist Circumference (cm)": round(waist_circumference, 2),
"Hip Circumference (cm)": round(hip_circumference, 2),
"Shoulder Width (cm)": round(shoulder_width_cm, 2),
"Torso Length (Neck to Pelvis, cm)": round(torso_length_cm, 2),
"Full Arm Length (Shoulder to Wrist, cm)": round(arm_length_cm, 2),
}
measurements = calculate_body_measurements(waist_circumference, hip_circumference, shoulder_width_cm, torso_length_cm, arm_length_cm)
return measurements, cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# Gradio Interface
demo = gr.Interface(
fn=process_image,
inputs=[gr.Image(type="pil"), gr.Number(label="User Height (cm)")],
outputs=[gr.JSON(label="Measurements"), gr.Image(type="pil", label="Keypoint Overlay")],
title="Keypoint Measurement Extractor",
description="Upload an image, enter your height, and get body measurements based on keypoints.",
)
demo.launch()