# 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 # import torch # import numpy as np # import cv2 # import json # import os # import gradio as gr # from detectron2.engine import DefaultPredictor # from detectron2.config import get_cfg # from detectron2 import model_zoo # # Output directory # 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" # predictor = DefaultPredictor(cfg) # def process_image(image, user_height_cm): # image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) # outputs = predictor(image) # 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 # with open(output_file, "w") as f: # json.dump({"keypoints": keypoints}, f, indent=4) # keypoints = np.array(keypoints[0])[:, :2] # 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_KNEE, R_KNEE = 13, 14 # L_ANKLE, R_ANKLE = 15, 16 # skeleton = [(5, 6), (5, 11), (6, 12), (11, 12)] # for x, y in keypoints: # cv2.circle(image, (int(x), int(y)), 5, (0, 255, 0), -1) # 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) # def get_distance(p1, p2): # return np.linalg.norm(np.array(p1) - np.array(p2)) # ankle_mid = ((keypoints[L_ANKLE] + keypoints[R_ANKLE]) / 2).tolist() # pixel_height = get_distance(keypoints[NOSE], ankle_mid) # estimated_full_pixel_height = pixel_height / 0.87 # pixels_per_cm = estimated_full_pixel_height / user_height_cm # shoulder_width_cm = get_distance(keypoints[L_SHOULDER], keypoints[R_SHOULDER]) / pixels_per_cm # waist_width_cm = get_distance(keypoints[L_HIP], keypoints[R_HIP]) / pixels_per_cm # pelvis = ((keypoints[L_HIP] + keypoints[R_HIP]) / 2).tolist() # neck = ((keypoints[L_SHOULDER] + keypoints[R_SHOULDER]) / 2).tolist() # torso_length_cm = get_distance(neck, pelvis) / pixels_per_cm # arm_length_cm = get_distance(keypoints[L_SHOULDER], keypoints[L_WRIST]) / pixels_per_cm # knee_mid = ((keypoints[L_KNEE] + keypoints[R_KNEE]) / 2).tolist() # neck_to_knee_cm = get_distance(neck, knee_mid) / pixels_per_cm # waist_circumference = np.pi * waist_width_cm # hip_circumference = waist_circumference / 0.75 # measurements = { # " Shoulder Width (cm)": round(shoulder_width_cm, 2), # " Waist Circumference (cm)": round(waist_circumference, 2), # " Hip Circumference (cm)": round(hip_circumference, 2), # " Torso Length (Neck to Pelvis, cm)": round(torso_length_cm, 2), # " Arm Length (Shoulder to Wrist, cm)": round(arm_length_cm, 2), # " Neck to Knee Length (cm)": round(neck_to_knee_cm, 2) # } # return measurements # # Gradio Interface # with gr.Blocks() as demo: # gr.Markdown("## 🧍 Keypoint-Based Body Measurement Tool") # gr.Markdown("Upload a **full-body image** and enter your **height (in cm)** to estimate body measurements using AI-powered keypoint detection.") # with gr.Row(): # with gr.Column(): # image_input = gr.Image(type="pil", label="📸 Upload Image") # # height_input = gr.Number(label="📏 Your Height (cm)", value=170) # submit_btn = gr.Button("🔍 Generate Measurements") # with gr.Column(): # height_input = gr.Number(label="📏 Your Height (cm)", value=170) # measurement_output = gr.JSON(label="📐 Estimated Measurements") # #image_output = gr.Image(type="pil", label="📌 Keypoint Overlay") # submit_btn.click(fn=process_image, inputs=[image_input, height_input], outputs=measurement_output) # demo.launch() import gradio as gr import json import base64 import requests from io import BytesIO import torch import numpy as np import cv2 import os from PIL import Image from detectron2.engine import DefaultPredictor from detectron2.config import get_cfg from detectron2 import model_zoo # === Set up Detectron2 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" predictor = DefaultPredictor(cfg) # === Utility === def get_distance(p1, p2): return np.linalg.norm(np.array(p1) - np.array(p2)) # === Keypoint and Measurement Logic === def process_image(image, user_height_cm): image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) outputs = predictor(image_cv) 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, None keypoints = np.array(keypoints[0])[:, :2] # Draw keypoints and skeleton skeleton = [(5, 6), (5, 11), (6, 12), (11, 12)] for x, y in keypoints: cv2.circle(image_cv, (int(x), int(y)), 5, (0, 255, 0), -1) for pt1, pt2 in skeleton: x1, y1 = map(int, keypoints[pt1]) x2, y2 = map(int, keypoints[pt2]) cv2.line(image_cv, (x1, y1), (x2, y2), (255, 0, 0), 2) # Body part indices NOSE, L_SHOULDER, R_SHOULDER = 0, 5, 6 L_WRIST, L_HIP, R_HIP, L_ANKLE, R_ANKLE = 9, 11, 12, 15, 16 ankle_mid = ((keypoints[L_ANKLE] + keypoints[R_ANKLE]) / 2).tolist() pixel_height = get_distance(keypoints[NOSE], ankle_mid) estimated_full_pixel_height = pixel_height / 0.87 pixels_per_cm = estimated_full_pixel_height / user_height_cm shoulder_width_cm = get_distance(keypoints[L_SHOULDER], keypoints[R_SHOULDER]) / pixels_per_cm waist_width_cm = get_distance(keypoints[L_HIP], keypoints[R_HIP]) / pixels_per_cm pelvis = ((keypoints[L_HIP] + keypoints[R_HIP]) / 2).tolist() neck = ((keypoints[L_SHOULDER] + keypoints[R_SHOULDER]) / 2).tolist() torso_length_cm = get_distance(neck, pelvis) / pixels_per_cm arm_length_cm = get_distance(keypoints[L_SHOULDER], keypoints[L_WRIST]) / pixels_per_cm waist_circumference = np.pi * waist_width_cm hip_circumference = waist_circumference / 0.75 measurements = { "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), } return measurements, cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB), keypoints.tolist() # === Save to DB === # def save_to_database(measurements, image, user_height_cm, user_id): # if not user_id: # return "❌ user_id missing from URL." # if measurements is None or image is None: # return "⚠️ No data to save." # buffered = BytesIO() # pil_image = Image.fromarray(image) # pil_image.save(buffered, format="JPEG") # img_str = base64.b64encode(buffered.getvalue()).decode("utf-8") # payload = { # "imageBase64": img_str, # "heightCm": user_height_cm, # "measurements": measurements # } # try: # response = requests.post( # f"https://9d68-210-212-162-140.ngrok-free.app/upload/{user_id}", # json=payload # ) # if response.status_code == 201: # return "✅ Measurements and image saved to database!" # else: # return f"❌ Failed: {response.status_code} - {response.text}" # except Exception as e: # return f"⚠️ Error during save: {str(e)}" def save_to_database(measurements, image, user_height_cm, user_id): if not user_id: return "❌ user_id missing from URL." if measurements is None or image is None: return "⚠️ No data to save." buffered = BytesIO() pil_image = Image.fromarray(image) pil_image.save(buffered, format="JPEG") img_str = base64.b64encode(buffered.getvalue()).decode("utf-8") payload = { "imageBase64": img_str, "heightCm": user_height_cm, "waistCircumferenceCm": measurements.get("Waist Circumference (cm)"), "hipcircumference": measurements.get("Hip Circumference (cm)"), "shoulderwidth": measurements.get("Shoulder Width (cm)"), "torsolength": measurements.get("Torso Length (Neck to Pelvis, cm)"), "fullarmlength": measurements.get("Full Arm Length (Shoulder to Wrist, cm)"), } try: response = requests.post( f" https://68be601de1e4.ngrok-free.app/upload/{user_id}", json=payload ) if response.status_code == 201: return "✅ Measurements and image saved to database!" else: return f"❌ Failed: {response.status_code} - {response.text}" except Exception as e: return f"⚠️ Error during save: {str(e)}" # === Gradio App === with gr.Blocks() as demo: gr.Markdown("# 📏 AI-Powered Body Measurement Tool") user_id_state = gr.State() @demo.load(inputs=None, outputs=[user_id_state]) def load_user_id(request: gr.Request): return request.query_params.get("user_id", "") with gr.Row(): with gr.Column(): image_input = gr.Image(label="Upload Your Full Body Image", type="pil") height_input = gr.Number(label="Your Real Height (in cm)") process_button = gr.Button("📐 Extract Measurements") with gr.Column(): output_image = gr.Image(label="Detected Keypoints") measurement_output = gr.JSON(label="Body Measurements") with gr.Row(): save_button = gr.Button("💾 Save to Backend") save_status = gr.Textbox(label="Status", interactive=False) # Store results for save processed_img = gr.State() processed_data = gr.State() process_button.click( fn=process_image, inputs=[image_input, height_input], outputs=[measurement_output, output_image, processed_data] ).then( fn=lambda img: img, inputs=[output_image], outputs=processed_img ) save_button.click( fn=save_to_database, inputs=[measurement_output, processed_img, height_input, user_id_state], outputs=save_status ) if __name__ == "__main__": demo.launch()