Update app.py
Browse files
app.py
CHANGED
@@ -4,8 +4,9 @@ import cv2
|
|
4 |
import numpy as np
|
5 |
from torchvision import transforms
|
6 |
from PIL import Image
|
|
|
7 |
|
8 |
-
# Load MiDaS depth estimation model
|
9 |
midas_model = torch.hub.load("intel-isl/MiDaS", "MiDaS_small")
|
10 |
midas_model.eval()
|
11 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
@@ -13,74 +14,59 @@ midas_model.to(device)
|
|
13 |
midas_transform = torch.hub.load("intel-isl/MiDaS", "transforms").default_transform
|
14 |
|
15 |
def estimate_depth(image):
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
# Convert PIL image to a NumPy array and normalize it
|
20 |
-
img_np = np.array(image, dtype=np.float32) / 255.0 # Normalize to [0, 1]
|
21 |
-
|
22 |
-
# Convert NumPy array to a Torch tensor
|
23 |
-
img_tensor = torch.tensor(img_np).permute(2, 0, 1).unsqueeze(0).to(device)
|
24 |
-
|
25 |
-
# Ensure tensor shape is [1, 3, H, W]
|
26 |
-
if img_tensor.dim() == 5: # If an extra batch dimension is present
|
27 |
-
img_tensor = img_tensor.squeeze(1)
|
28 |
-
|
29 |
with torch.no_grad():
|
30 |
depth = midas_model(img_tensor).squeeze().cpu().numpy()
|
31 |
-
|
32 |
depth = cv2.resize(depth, (image.size[0], image.size[1]))
|
33 |
depth = (depth - depth.min()) / (depth.max() - depth.min()) * 255
|
34 |
return depth.astype(np.uint8)
|
35 |
|
36 |
-
def
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
h, w = depth.shape
|
39 |
grid_x, grid_y = np.meshgrid(np.arange(w), np.arange(h))
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
|
|
|
|
|
|
|
|
50 |
|
51 |
def blend_design(cloth_img, design_img):
|
52 |
-
"""Blend design onto clothing naturally with fold adaptation using TPS warping."""
|
53 |
cloth_img = cloth_img.convert("RGB")
|
54 |
design_img = design_img.convert("RGBA")
|
55 |
cloth_np = np.array(cloth_img)
|
56 |
design_np = np.array(design_img)
|
57 |
-
|
58 |
-
# Resize design
|
59 |
h, w, _ = cloth_np.shape
|
60 |
dh, dw, _ = design_np.shape
|
61 |
scale_factor = min(w / dw, h / dh) * 0.4
|
62 |
new_w, new_h = int(dw * scale_factor), int(dh * scale_factor)
|
63 |
design_np = cv2.resize(design_np, (new_w, new_h), interpolation=cv2.INTER_AREA)
|
64 |
-
|
65 |
-
# Extract alpha channel
|
66 |
alpha_channel = design_np[:, :, 3] / 255.0
|
67 |
design_np = design_np[:, :, :3]
|
68 |
-
|
69 |
-
# Create placement area
|
70 |
x_offset = (w - new_w) // 2
|
71 |
y_offset = int(h * 0.35)
|
72 |
design_canvas = np.zeros_like(cloth_np)
|
73 |
design_canvas[y_offset:y_offset+new_h, x_offset:x_offset+new_w] = design_np
|
74 |
-
|
75 |
-
# Estimate depth and apply TPS warping
|
76 |
depth_map = estimate_depth(cloth_img)
|
77 |
-
warped_design =
|
78 |
-
|
79 |
-
|
80 |
-
mask = np.zeros_like(cloth_np, dtype=np.float32)
|
81 |
-
mask[y_offset:y_offset+new_h, x_offset:x_offset+new_w] = np.expand_dims(alpha_channel, axis=-1)
|
82 |
-
cloth_np = (cloth_np * (1 - mask) + warped_design * mask).astype(np.uint8)
|
83 |
-
|
84 |
return Image.fromarray(cloth_np)
|
85 |
|
86 |
def main(cloth, design):
|
|
|
4 |
import numpy as np
|
5 |
from torchvision import transforms
|
6 |
from PIL import Image
|
7 |
+
from scipy.interpolate import Rbf
|
8 |
|
9 |
+
# Load MiDaS depth estimation model
|
10 |
midas_model = torch.hub.load("intel-isl/MiDaS", "MiDaS_small")
|
11 |
midas_model.eval()
|
12 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
|
14 |
midas_transform = torch.hub.load("intel-isl/MiDaS", "transforms").default_transform
|
15 |
|
16 |
def estimate_depth(image):
|
17 |
+
image = image.convert("RGB")
|
18 |
+
img_tensor = midas_transform(image).to(device)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
with torch.no_grad():
|
20 |
depth = midas_model(img_tensor).squeeze().cpu().numpy()
|
|
|
21 |
depth = cv2.resize(depth, (image.size[0], image.size[1]))
|
22 |
depth = (depth - depth.min()) / (depth.max() - depth.min()) * 255
|
23 |
return depth.astype(np.uint8)
|
24 |
|
25 |
+
def compute_optical_flow(depth):
|
26 |
+
depth_blurred = cv2.GaussianBlur(depth, (5, 5), 0)
|
27 |
+
flow = cv2.calcOpticalFlowFarneback(depth_blurred, depth, None, 0.5, 3, 15, 3, 5, 1.2, 0)
|
28 |
+
displacement_x = cv2.normalize(flow[..., 0], None, -5, 5, cv2.NORM_MINMAX)
|
29 |
+
displacement_y = cv2.normalize(flow[..., 1], None, -5, 5, cv2.NORM_MINMAX)
|
30 |
+
return displacement_x, displacement_y
|
31 |
+
|
32 |
+
def apply_tps_interpolation(design, depth):
|
33 |
h, w = depth.shape
|
34 |
grid_x, grid_y = np.meshgrid(np.arange(w), np.arange(h))
|
35 |
+
edges = cv2.Canny(depth.astype(np.uint8), 50, 150)
|
36 |
+
points = np.column_stack(np.where(edges > 0))
|
37 |
+
tps_x = Rbf(points[:, 1], points[:, 0], grid_x[points[:, 0], points[:, 1]], function="thin_plate")
|
38 |
+
tps_y = Rbf(points[:, 1], points[:, 0], grid_y[points[:, 0], points[:, 1]], function="thin_plate")
|
39 |
+
map_x = tps_x(grid_x, grid_y).astype(np.float32)
|
40 |
+
map_y = tps_y(grid_x, grid_y).astype(np.float32)
|
41 |
+
return cv2.remap(design, map_x, map_y, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT)
|
42 |
+
|
43 |
+
def compute_adaptive_alpha(depth):
|
44 |
+
grad_x = cv2.Sobel(depth, cv2.CV_32F, 1, 0, ksize=3)
|
45 |
+
grad_y = cv2.Sobel(depth, cv2.CV_32F, 0, 1, ksize=3)
|
46 |
+
grad_magnitude = np.sqrt(grad_x**2 + grad_y**2)
|
47 |
+
alpha = cv2.normalize(grad_magnitude, None, 0, 1, cv2.NORM_MINMAX)
|
48 |
+
return alpha
|
49 |
|
50 |
def blend_design(cloth_img, design_img):
|
|
|
51 |
cloth_img = cloth_img.convert("RGB")
|
52 |
design_img = design_img.convert("RGBA")
|
53 |
cloth_np = np.array(cloth_img)
|
54 |
design_np = np.array(design_img)
|
|
|
|
|
55 |
h, w, _ = cloth_np.shape
|
56 |
dh, dw, _ = design_np.shape
|
57 |
scale_factor = min(w / dw, h / dh) * 0.4
|
58 |
new_w, new_h = int(dw * scale_factor), int(dh * scale_factor)
|
59 |
design_np = cv2.resize(design_np, (new_w, new_h), interpolation=cv2.INTER_AREA)
|
|
|
|
|
60 |
alpha_channel = design_np[:, :, 3] / 255.0
|
61 |
design_np = design_np[:, :, :3]
|
|
|
|
|
62 |
x_offset = (w - new_w) // 2
|
63 |
y_offset = int(h * 0.35)
|
64 |
design_canvas = np.zeros_like(cloth_np)
|
65 |
design_canvas[y_offset:y_offset+new_h, x_offset:x_offset+new_w] = design_np
|
|
|
|
|
66 |
depth_map = estimate_depth(cloth_img)
|
67 |
+
warped_design = apply_tps_interpolation(design_canvas, depth_map)
|
68 |
+
adaptive_alpha = compute_adaptive_alpha(depth_map)
|
69 |
+
cloth_np = (cloth_np * (1 - adaptive_alpha) + warped_design * adaptive_alpha).astype(np.uint8)
|
|
|
|
|
|
|
|
|
70 |
return Image.fromarray(cloth_np)
|
71 |
|
72 |
def main(cloth, design):
|