import gradio as gr import torch import cv2 import numpy as np from torchvision import transforms from PIL import Image from transformers import DPTForDepthEstimation, DPTFeatureExtractor, MidasForDepthEstimation, MidasImageProcessor # Load depth estimation model (MiDaS v3 for better accuracy) model_name = "Intel/midas-v3" # Upgraded model processor = MidasImageProcessor.from_pretrained(model_name) depth_model = MidasForDepthEstimation.from_pretrained(model_name) depth_model.eval() def estimate_depth(image): """Estimate depth map from image using MiDaS v3.""" image = image.convert("RGB") inputs = processor(images=image, return_tensors="pt") with torch.no_grad(): outputs = depth_model(**inputs) depth = outputs.predicted_depth.squeeze().cpu().numpy() depth = cv2.resize(depth, (image.width, image.height)) depth = (depth - depth.min()) / (depth.max() - depth.min()) * 255 return depth.astype(np.uint8) def apply_tps_warping(design, depth): """Apply Thin Plate Spline (TPS) warping based on depth.""" h, w = depth.shape grid_x, grid_y = np.meshgrid(np.arange(w), np.arange(h)) displacement_x = cv2.Sobel(depth, cv2.CV_32F, 1, 0, ksize=5) displacement_y = cv2.Sobel(depth, cv2.CV_32F, 0, 1, ksize=5) displacement_x = cv2.normalize(displacement_x, None, -10, 10, cv2.NORM_MINMAX) displacement_y = cv2.normalize(displacement_y, None, -10, 10, cv2.NORM_MINMAX) map_x = np.clip(grid_x + displacement_x, 0, w - 1).astype(np.float32) map_y = np.clip(grid_y + displacement_y, 0, h - 1).astype(np.float32) warped_design = cv2.remap(design, map_x, map_y, interpolation=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REFLECT) return warped_design def blend_design(cloth_img, design_img): """Blend design onto clothing naturally with fold adaptation using TPS warping.""" cloth_img = cloth_img.convert("RGB") design_img = design_img.convert("RGBA") cloth_np = np.array(cloth_img) design_np = np.array(design_img) # Resize design h, w, _ = cloth_np.shape dh, dw, _ = design_np.shape scale_factor = min(w / dw, h / dh) * 0.4 new_w, new_h = int(dw * scale_factor), int(dh * scale_factor) design_np = cv2.resize(design_np, (new_w, new_h), interpolation=cv2.INTER_AREA) # Extract alpha channel alpha_channel = design_np[:, :, 3] / 255.0 design_np = design_np[:, :, :3] # Create placement area x_offset = (w - new_w) // 2 y_offset = int(h * 0.35) design_canvas = np.zeros_like(cloth_np) design_canvas[y_offset:y_offset+new_h, x_offset:x_offset+new_w] = design_np # Estimate depth and apply TPS warping depth_map = estimate_depth(cloth_img) warped_design = apply_tps_warping(design_canvas, depth_map) # Blend design onto cloth for c in range(3): cloth_np[:, :, c] = (cloth_np[:, :, c] * (1 - alpha_channel) + warped_design[:, :, c] * alpha_channel) return Image.fromarray(cloth_np) def main(cloth, design): return blend_design(cloth, design) iface = gr.Interface( fn=main, inputs=[gr.Image(type="pil"), gr.Image(type="pil")], outputs=gr.Image(type="pil"), title="AI Cloth Design Warping", description="Upload a clothing image and a design to blend it naturally, ensuring it stays centered and follows fabric folds." ) if __name__ == "__main__": iface.launch(share=True)