ZynkDev commited on
Commit
6d767ef
·
verified ·
1 Parent(s): 633ea8e

Upload 6 files

Browse files
Files changed (3) hide show
  1. README.md +5 -0
  2. cloth_warper.py +45 -0
  3. pose_estimator.py +81 -0
README.md CHANGED
@@ -23,6 +23,11 @@ This folder contains the AR overlay modules and dependency pins to apply on top
23
 
24
  ## How to apply
25
 
 
 
 
 
 
26
  1. Duplicate yisol/IDM-VTON into your own Space.
27
  2. Copy pipeline/\*.py into the Space pipeline folder.
28
  3. Merge AR endpoint function into app.py and expose api_name as ar_overlay.
 
23
 
24
  ## How to apply
25
 
26
+ Important: This package is a merge patch, not a full Space repository.
27
+ Do not replace the whole duplicated Space with only these files.
28
+ Keep the original `app.py` from the duplicated IDM-VTON Space (or provide your own `app.py` that calls `launch()`).
29
+ If `app.py` is missing or exits immediately, Space can fail with messages like "signal is aborted without reason" or exit code 0.
30
+
31
  1. Duplicate yisol/IDM-VTON into your own Space.
32
  2. Copy pipeline/\*.py into the Space pipeline folder.
33
  3. Merge AR endpoint function into app.py and expose api_name as ar_overlay.
cloth_warper.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+ import numpy as np
3
+
4
+
5
+ def remove_white_background(img_pil: Image.Image, threshold: int = 240) -> Image.Image:
6
+ rgba = img_pil.convert("RGBA")
7
+ data = np.array(rgba)
8
+ r, g, b, a = data[:, :, 0], data[:, :, 1], data[:, :, 2], data[:, :, 3]
9
+
10
+ white_mask = (r > threshold) & (g > threshold) & (b > threshold)
11
+ data[:, :, 3] = np.where(white_mask, 0, a)
12
+ return Image.fromarray(data)
13
+
14
+
15
+ def warp_cloth_to_torso(
16
+ cloth_pil: Image.Image,
17
+ torso_box: tuple,
18
+ image_size: tuple,
19
+ alpha: float = 0.78,
20
+ ) -> Image.Image:
21
+ width, height = image_size
22
+ x1, y1, x2, y2 = torso_box
23
+
24
+ region_w = x2 - x1
25
+ region_h = y2 - y1
26
+
27
+ if region_w <= 0 or region_h <= 0:
28
+ return Image.new("RGBA", (width, height), (0, 0, 0, 0))
29
+
30
+ cloth_rgba = remove_white_background(cloth_pil)
31
+ cloth_resized = cloth_rgba.resize((region_w, region_h), Image.LANCZOS)
32
+
33
+ r, g, b, a = cloth_resized.split()
34
+ a = a.point(lambda px: int(px * alpha))
35
+ cloth_resized = Image.merge("RGBA", (r, g, b, a))
36
+
37
+ canvas = Image.new("RGBA", (width, height), (0, 0, 0, 0))
38
+ canvas.paste(cloth_resized, (x1, y1), cloth_resized)
39
+ return canvas
40
+
41
+
42
+ def blend_on_person(person_pil: Image.Image, cloth_canvas: Image.Image) -> Image.Image:
43
+ person_rgba = person_pil.convert("RGBA")
44
+ result = Image.alpha_composite(person_rgba, cloth_canvas)
45
+ return result.convert("RGB")
pose_estimator.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MediaPipe Pose for AR overlay tab
2
+
3
+ from PIL import Image
4
+ import mediapipe as mp
5
+ import numpy as np
6
+
7
+ mp_pose = mp.solutions.pose
8
+ mp_drawing = mp.solutions.drawing_utils
9
+
10
+ LANDMARK = mp_pose.PoseLandmark
11
+ TORSO_INDICES = [
12
+ LANDMARK.LEFT_SHOULDER.value,
13
+ LANDMARK.RIGHT_SHOULDER.value,
14
+ LANDMARK.LEFT_HIP.value,
15
+ LANDMARK.RIGHT_HIP.value,
16
+ ]
17
+
18
+
19
+ def extract_pose_mediapipe(image_pil: Image.Image):
20
+ img_rgb = np.array(image_pil.convert("RGB"))
21
+ height, width = img_rgb.shape[:2]
22
+
23
+ with mp_pose.Pose(
24
+ static_image_mode=True,
25
+ model_complexity=1,
26
+ enable_segmentation=False,
27
+ min_detection_confidence=0.5,
28
+ min_tracking_confidence=0.5,
29
+ ) as pose:
30
+ results = pose.process(img_rgb)
31
+
32
+ if not results.pose_landmarks:
33
+ return None
34
+
35
+ landmarks_raw = results.pose_landmarks.landmark
36
+
37
+ landmarks = {}
38
+ for idx, name in enumerate(LANDMARK):
39
+ px = int(landmarks_raw[idx].x * width)
40
+ py = int(landmarks_raw[idx].y * height)
41
+ landmarks[name.name] = (px, py)
42
+
43
+ skeleton_canvas = np.zeros_like(img_rgb)
44
+ mp_drawing.draw_landmarks(
45
+ skeleton_canvas,
46
+ results.pose_landmarks,
47
+ mp_pose.POSE_CONNECTIONS,
48
+ landmark_drawing_spec=mp_drawing.DrawingSpec(
49
+ color=(0, 255, 200), thickness=2, circle_radius=4
50
+ ),
51
+ connection_drawing_spec=mp_drawing.DrawingSpec(color=(100, 180, 255), thickness=2),
52
+ )
53
+
54
+ torso_x = [landmarks_raw[idx].x * width for idx in TORSO_INDICES]
55
+ torso_y = [landmarks_raw[idx].y * height for idx in TORSO_INDICES]
56
+
57
+ pad_x = int((max(torso_x) - min(torso_x)) * 0.12)
58
+ pad_y_top = int((max(torso_y) - min(torso_y)) * 0.08)
59
+ pad_y_bottom = int((max(torso_y) - min(torso_y)) * 0.05)
60
+
61
+ x1 = max(0, int(min(torso_x)) - pad_x)
62
+ y1 = max(0, int(min(torso_y)) - pad_y_top)
63
+ x2 = min(width, int(max(torso_x)) + pad_x)
64
+ y2 = min(height, int(max(torso_y)) + pad_y_bottom)
65
+
66
+ return {
67
+ "landmarks": landmarks,
68
+ "skeleton_pil": Image.fromarray(skeleton_canvas),
69
+ "torso_box": (x1, y1, x2, y2),
70
+ "image_size": (width, height),
71
+ }
72
+
73
+
74
+ def draw_skeleton_overlay(image_pil: Image.Image, pose_data: dict, alpha: float = 0.6):
75
+ base = np.array(image_pil.convert("RGB")).astype(float)
76
+ skeleton = np.array(pose_data["skeleton_pil"].convert("RGB")).astype(float)
77
+
78
+ skeleton_mask = (skeleton.sum(axis=2) > 0).astype(float)[:, :, np.newaxis]
79
+ blended = base * (1 - skeleton_mask * alpha) + skeleton * skeleton_mask * alpha
80
+
81
+ return Image.fromarray(blended.astype(np.uint8))