Spaces:
Paused
Paused
| # 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() | |
| 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() | |