ssoxye commited on
Commit
4d41e0b
·
1 Parent(s): 6d019a0

update garment pil

Browse files
Files changed (1) hide show
  1. app.py +31 -496
app.py CHANGED
@@ -1,499 +1,3 @@
1
- # import os
2
- # import sys
3
-
4
- # # ---------------------------------------------------------
5
- # # 0) Make sure local packages (diffusers3, preprocess, etc.) are importable on HF Spaces
6
- # # ---------------------------------------------------------
7
- # ROOT = os.path.dirname(os.path.abspath(__file__))
8
- # if ROOT not in sys.path:
9
- # sys.path.insert(0, ROOT)
10
-
11
- # print("[BOOT] ROOT =", ROOT, flush=True)
12
- # print("[BOOT] sys.path[:5] =", sys.path[:5], flush=True)
13
-
14
- # import tempfile
15
- # from dataclasses import dataclass
16
- # from functools import lru_cache
17
- # from typing import Optional, Tuple
18
-
19
- # import gradio as gr
20
- # import torch
21
- # import numpy as np
22
- # import cv2
23
- # import imageio
24
- # from PIL import Image, ImageOps
25
-
26
- # from huggingface_hub import hf_hub_download
27
-
28
- # from diffusers import UniPCMultistepScheduler
29
-
30
- # # Show where diffusers3 is imported from (helps diagnose import collisions on Spaces)
31
- # import diffusers3
32
- # print("[BOOT] diffusers3 loaded from:", getattr(diffusers3, "__file__", "<?>"), flush=True)
33
-
34
- # from diffusers3.models.controlnet import ControlNetModel
35
- # from diffusers3.pipelines.controlnet.pipeline_controlnet_sd_xl_img2img_img import (
36
- # StableDiffusionXLControlNetImg2ImgPipeline,
37
- # )
38
- # from ip_adapter import IPAdapterXL
39
-
40
- # # 너 코드에서 쓰는 extractor API 그대로( run(category, input_path, model_restore=...) )
41
- # from preprocess.simple_extractor import run as run_simple_extractor
42
-
43
-
44
- # # =========================
45
- # # HF Hub repo ids
46
- # # =========================
47
- # BASE_MODEL_ID = "stabilityai/stable-diffusion-xl-base-1.0"
48
- # CONTROLNET_ID = "diffusers/controlnet-depth-sdxl-1.0"
49
-
50
- # # 네 assets dataset repo (가중치 저장소)
51
- # ASSETS_REPO = os.getenv("ASSETS_REPO", "soye/VISTA_assets")
52
- # ASSETS_REPO_TYPE = "dataset" # dataset repo로 올렸으니
53
-
54
-
55
- # def asset_path(relpath: str) -> str:
56
- # """
57
- # relpath 예:
58
- # - "image_encoder/model.safetensors"
59
- # - "image_encoder/config.json"
60
- # - "ip_adapter/ip-adapter_sdxl_vit-h.bin"
61
- # - "preprocess_ckpts/exp-schp-201908301523-atr.pth"
62
- # """
63
- # return hf_hub_download(
64
- # repo_id=ASSETS_REPO,
65
- # repo_type=ASSETS_REPO_TYPE,
66
- # filename=relpath,
67
- # )
68
-
69
-
70
- # @lru_cache(maxsize=1)
71
- # def get_assets():
72
- # """
73
- # Lazily downloads required assets on first use.
74
-
75
- # Returns:
76
- # (image_encoder_dir, ip_ckpt_path, schp_ckpt_path)
77
- # """
78
- # print("[ASSETS] Downloading assets from:", ASSETS_REPO, flush=True)
79
-
80
- # # Image encoder folder is needed by IPAdapterXL
81
- # image_encoder_weight = asset_path("image_encoder/model.safetensors")
82
- # _ = asset_path("image_encoder/config.json") # ensure config exists locally
83
- # image_encoder_dir = os.path.dirname(image_encoder_weight)
84
-
85
- # ip_ckpt = asset_path("ip_adapter/ip-adapter_sdxl_vit-h.bin")
86
- # schp_ckpt = asset_path("preprocess_ckpts/exp-schp-201908301523-atr.pth")
87
-
88
- # print("[ASSETS] image_encoder_dir =", image_encoder_dir, flush=True)
89
- # print("[ASSETS] ip_ckpt =", ip_ckpt, flush=True)
90
- # print("[ASSETS] schp_ckpt =", schp_ckpt, flush=True)
91
- # return image_encoder_dir, ip_ckpt, schp_ckpt
92
-
93
-
94
- # DEFAULT_STEPS = 40
95
- # DEBUG_SAVE = False
96
-
97
- # # 전역 resize params
98
- # H: Optional[int] = None # 1024
99
- # W: Optional[int] = None # aspect 유지 기반
100
-
101
-
102
- # @dataclass
103
- # class Paths:
104
- # person_path: str
105
- # depth_path: str
106
- # style_path: str
107
- # output_path: str
108
-
109
-
110
- # def _imread_or_raise(path: str, flag=cv2.IMREAD_COLOR):
111
- # img = cv2.imread(path, flag)
112
- # if img is None:
113
- # raise FileNotFoundError(f"cv2.imread failed: {path} (exists={os.path.exists(path)})")
114
- # return img
115
-
116
-
117
- # def compute_hw_from_person(person_path: str):
118
- # """
119
- # - height=1024 고정, aspect 유지로 W 계산
120
- # - demo 안정성 위해 W를 1024로 cap.
121
- # """
122
- # img = _imread_or_raise(person_path)
123
- # orig_h, orig_w = img.shape[:2]
124
- # scale = 1024.0 / float(orig_h)
125
- # new_h = 1024
126
- # new_w = int(round(orig_w * scale))
127
- # if new_w > 1024:
128
- # new_w = 1024
129
- # return new_h, new_w
130
-
131
-
132
- # def invert_sketch_area(sketch_pil: Image.Image) -> Image.Image:
133
- # return ImageOps.invert(sketch_pil.convert("L")).convert("RGB")
134
-
135
-
136
- # def fill_sketch_from_image_path_to_pil(image_path: str) -> Image.Image:
137
- # global H, W
138
- # if H is None or W is None:
139
- # raise RuntimeError("Global H/W not set.")
140
- # img = _imread_or_raise(image_path, cv2.IMREAD_GRAYSCALE)
141
- # img = cv2.resize(img, (W, H), interpolation=cv2.INTER_NEAREST)
142
- # _, binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
143
- # contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
144
- # filled = np.zeros_like(binary)
145
- # cv2.drawContours(filled, contours, -1, 255, thickness=cv2.FILLED)
146
- # filled_rgb = cv2.cvtColor(filled, cv2.COLOR_GRAY2RGB)
147
- # return Image.fromarray(filled_rgb)
148
-
149
-
150
- # def merge_white_regions_or(img1: Image.Image, img2: Image.Image) -> Image.Image:
151
- # a = np.array(img1.convert("RGB"), dtype=np.uint8)
152
- # b = np.array(img2.convert("RGB"), dtype=np.uint8)
153
- # white_a = np.all(a == 255, axis=-1)
154
- # white_b = np.all(b == 255, axis=-1)
155
- # out = a.copy()
156
- # out[white_a | white_b] = 255
157
- # return Image.fromarray(out)
158
-
159
-
160
- # def preprocess_mask(mask_img: Image.Image) -> Image.Image:
161
- # """
162
- # (2번째 첨부 코드 규칙 반영)
163
- # - 입력(mask_img)을 전역 (W,H)로 resize (NEAREST)
164
- # - 이진화(threshold)
165
- # - padding 목표 width는 항상 1024로 고정
166
- # * width < 1024: 좌/우 padding (value=0)
167
- # * width > 1024: 중앙 crop
168
- # - dilation (kernel 17x17, iter=1)
169
- # - return: RGB mask PIL
170
- # """
171
- # global H, W
172
-
173
- # # 1) to grayscale np
174
- # m = np.array(mask_img.convert("L"), dtype=np.uint8)
175
-
176
- # # 2) resize to global (W, H) (2번째 코드의 "resize는 전역 (W,H)" 컨벤션)
177
- # if (H is not None) and (W is not None):
178
- # # mask는 경계 보존 위해 NEAREST 권장
179
- # m = cv2.resize(m, (W, H), interpolation=cv2.INTER_NEAREST)
180
-
181
- # # 3) binarize
182
- # _, m = cv2.threshold(m, 127, 255, cv2.THRESH_BINARY)
183
-
184
- # # 4) pad/crop to target width=1024 (항상 고정)
185
- # target_width = 1024
186
- # h, w = m.shape[:2]
187
-
188
- # if w < target_width:
189
- # total_padding = target_width - w
190
- # left_padding = total_padding // 2
191
- # right_padding = total_padding - left_padding
192
- # m = cv2.copyMakeBorder(
193
- # m,
194
- # top=0, bottom=0,
195
- # left=left_padding, right=right_padding,
196
- # borderType=cv2.BORDER_CONSTANT,
197
- # value=0,
198
- # )
199
- # elif w > target_width:
200
- # left = (w - target_width) // 2
201
- # m = m[:, left:left + target_width]
202
-
203
- # # 5) dilate (2번째 코드 동일)
204
- # kernel = np.ones((17, 17), np.uint8)
205
- # m = cv2.dilate(m, kernel, iterations=1)
206
-
207
- # if DEBUG_SAVE:
208
- # cv2.imwrite("mask_final_1024.png", m)
209
-
210
- # # 6) return as RGB PIL
211
- # return Image.fromarray(m, mode="L").convert("RGB")
212
-
213
-
214
-
215
- # def make_depth(depth_path: str) -> Image.Image:
216
- # global H, W
217
- # if H is None or W is None:
218
- # raise RuntimeError("Global H/W not set.")
219
- # depth_img = _imread_or_raise(depth_path, 0)
220
- # inverted = cv2.bitwise_not(depth_img)
221
- # contours, _ = cv2.findContours(inverted, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
222
- # filled = inverted.copy()
223
- # cv2.drawContours(filled, contours, -1, (255), thickness=cv2.FILLED)
224
- # filled = cv2.resize(filled, (W, H), interpolation=cv2.INTER_AREA)
225
- # filled_rgb = cv2.cvtColor(filled, cv2.COLOR_GRAY2RGB)
226
-
227
- # target_width = 1024
228
- # cur_w = filled_rgb.shape[1]
229
- # if cur_w < target_width:
230
- # pad = (target_width - cur_w) // 2
231
- # filled_rgb = cv2.copyMakeBorder(
232
- # filled_rgb, 0, 0, pad, pad,
233
- # borderType=cv2.BORDER_CONSTANT, value=[0, 0, 0]
234
- # )
235
- # elif cur_w > target_width:
236
- # left = (cur_w - target_width) // 2
237
- # filled_rgb = filled_rgb[:, left:left + target_width]
238
- # return Image.fromarray(filled_rgb)
239
-
240
-
241
- # def center_crop_lr_to_768x1024(arr: np.ndarray) -> np.ndarray:
242
- # target_h, target_w = 1024, 768
243
- # h, w = arr.shape[:2]
244
- # if h != target_h:
245
- # arr = cv2.resize(arr, (w, target_h), interpolation=cv2.INTER_AREA)
246
- # h, w = arr.shape[:2]
247
- # if w < target_w:
248
- # pad = (target_w - w) // 2
249
- # arr = cv2.copyMakeBorder(arr, 0, 0, pad, pad, cv2.BORDER_CONSTANT, value=[255, 255, 255])
250
- # w = arr.shape[1]
251
- # left = (w - target_w) // 2
252
- # return arr[:, left:left + target_w]
253
-
254
-
255
- # def save_cropped(imgs, out_path: str):
256
- # np_imgs = [np.asarray(im) for im in imgs]
257
- # cropped = [center_crop_lr_to_768x1024(x) for x in np_imgs]
258
- # out = np.concatenate(cropped, axis=1)
259
- # os.makedirs(os.path.dirname(out_path), exist_ok=True)
260
- # imageio.imsave(out_path, out)
261
-
262
- # from diffusers import UniPCMultistepScheduler, AutoencoderKL, UNet2DConditionModel
263
-
264
- # @lru_cache(maxsize=1)
265
- # def get_pipe_and_device() -> Tuple[StableDiffusionXLControlNetImg2ImgPipeline, str, torch.dtype]:
266
- # device = "cuda" if torch.cuda.is_available() else "cpu"
267
- # dtype = torch.float32 if device == "cuda" else torch.float32
268
-
269
- # print(f"[PIPE] device={device}, dtype={dtype}", flush=True)
270
-
271
- # # ControlNet
272
- # controlnet = ControlNetModel.from_pretrained(
273
- # CONTROLNET_ID,
274
- # torch_dtype=dtype,
275
- # use_safetensors=True,
276
- # ).to(device)
277
-
278
- # # ✅ VAE: safetensors 강제 로드 후 주입
279
- # vae = AutoencoderKL.from_pretrained(
280
- # BASE_MODEL_ID,
281
- # subfolder="vae",
282
- # torch_dtype=dtype,
283
- # use_safetensors=True,
284
- # ).to(device)
285
-
286
- # # ✅ UNet: safetensors 강제 로드 후 주입
287
- # unet = UNet2DConditionModel.from_pretrained(
288
- # BASE_MODEL_ID,
289
- # subfolder="unet",
290
- # torch_dtype=dtype,
291
- # use_safetensors=True,
292
- # ).to(device)
293
-
294
- # # Pipeline
295
- # pipe = StableDiffusionXLControlNetImg2ImgPipeline.from_pretrained(
296
- # BASE_MODEL_ID,
297
- # controlnet=controlnet,
298
- # vae=vae,
299
- # unet=unet,
300
- # torch_dtype=dtype,
301
- # use_safetensors=True,
302
- # add_watermarker=False,
303
- # ).to(device)
304
-
305
- # # dtype mismatch 방지(vae)
306
- # if device == "cuda":
307
- # try:
308
- # pipe.vae.to(dtype=dtype)
309
- # if hasattr(pipe.vae, "config") and hasattr(pipe.vae.config, "force_upcast"):
310
- # pipe.vae.config.force_upcast = False
311
- # except Exception as e:
312
- # print("[PIPE] VAE dtype cast failed:", repr(e), flush=True)
313
-
314
- # pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
315
- # pipe.enable_attention_slicing()
316
- # try:
317
- # pipe.enable_xformers_memory_efficient_attention()
318
- # except Exception as e:
319
- # print("[PIPE] xformers not enabled:", repr(e), flush=True)
320
-
321
- # return pipe, device, dtype
322
-
323
-
324
-
325
-
326
- # def run_one(paths: Paths, prompt: str, steps: int = DEFAULT_STEPS):
327
- # global H, W
328
- # pipe, device, _dtype = get_pipe_and_device()
329
-
330
- # # lazy assets download here (NOT at import time)
331
- # image_encoder_dir, ip_ckpt, schp_ckpt = get_assets()
332
-
333
- # H, W = compute_hw_from_person(paths.person_path)
334
-
335
- # # parsing extractor (원본 호출 형태 유지)
336
- # res = run_simple_extractor(
337
- # category="Upper-clothes",
338
- # input_path=os.path.abspath(paths.person_path),
339
- # model_restore=schp_ckpt,
340
- # )
341
- # parsing_img = res["images"][0] if res.get("images") else None
342
- # if parsing_img is None:
343
- # raise RuntimeError("run_simple_extractor returned no parsing images.")
344
-
345
- # sketch_area = fill_sketch_from_image_path_to_pil(paths.depth_path)
346
- # sketch_area_inv = invert_sketch_area(sketch_area)
347
- # merged_img = merge_white_regions_or(parsing_img, sketch_area_inv)
348
- # mask_pil = preprocess_mask(merged_img)
349
-
350
- # # person resize + width=1024 pad/crop
351
- # person_bgr = _imread_or_raise(paths.person_path)
352
- # person_bgr = cv2.resize(person_bgr, (W, H), interpolation=cv2.INTER_AREA)
353
-
354
- # target_width = 1024
355
- # cur_w = person_bgr.shape[1]
356
- # if cur_w < target_width:
357
- # pad = (target_width - cur_w) // 2
358
- # padded_person = cv2.copyMakeBorder(
359
- # person_bgr, 0, 0, pad, pad,
360
- # borderType=cv2.BORDER_CONSTANT, value=[255, 255, 255]
361
- # )
362
- # elif cur_w > target_width:
363
- # left = (cur_w - target_width) // 2
364
- # padded_person = person_bgr[:, left:left + target_width]
365
- # else:
366
- # padded_person = person_bgr
367
-
368
- # person_rgb = cv2.cvtColor(padded_person, cv2.COLOR_BGR2RGB)
369
- # person_pil = Image.fromarray(person_rgb)
370
-
371
- # depth_map = make_depth(paths.depth_path)
372
-
373
- # # garment / garment_mask
374
- # garment_pil = person_pil.copy()
375
-
376
- # gm = np.array(parsing_img.convert("L"), dtype=np.uint8)
377
- # gm = cv2.resize(gm, (W, H), interpolation=cv2.INTER_AREA)
378
- # gm = cv2.cvtColor(gm, cv2.COLOR_GRAY2RGB)
379
- # cur_w2 = gm.shape[1]
380
- # if cur_w2 < target_width:
381
- # pad2 = (target_width - cur_w2) // 2
382
- # gm = cv2.copyMakeBorder(gm, 0, 0, pad2, pad2, cv2.BORDER_CONSTANT, value=[0, 0, 0])
383
- # elif cur_w2 > target_width:
384
- # left2 = (cur_w2 - target_width) // 2
385
- # gm = gm[:, left2:left2 + target_width]
386
- # garment_mask_pil = Image.fromarray(gm)
387
-
388
- # ip_model = IPAdapterXL(
389
- # pipe,
390
- # image_encoder_dir,
391
- # ip_ckpt,
392
- # device,
393
- # mask_pil,
394
- # person_pil,
395
- # content_scale=0.3,
396
- # style_scale=0.5,
397
- # garment_images=garment_pil,
398
- # garment_mask=garment_mask_pil,
399
- # )
400
-
401
-
402
- # if device == "cuda":
403
- # pipe.to(dtype=torch.float32)
404
- # try:
405
- # for _, proc in pipe.unet.attn_processors.items():
406
- # proc.to(dtype=torch.float32)
407
- # except Exception:
408
- # pass
409
-
410
-
411
-
412
-
413
- # style_img = Image.open(paths.style_path).convert("RGB")
414
-
415
- # person_pil.save('./person_pil.png')
416
- # person_pil.save('./mask_pil.png')
417
- # depth_map.save('./depth_map.png')
418
- # garment_pil.save('./garment_pil.png')
419
- # garment_mask_pil.save('./garment_mask_pil.png')
420
-
421
- # with torch.inference_mode():
422
- # images = ip_model.generate(
423
- # pil_image=style_img,
424
- # image=person_pil,
425
- # control_image=depth_map,
426
- # strength=1.0,
427
- # num_samples=1,
428
- # num_inference_steps=int(steps),
429
- # shape_prompt="",
430
- # prompt=prompt or "",
431
- # num=0,
432
- # scale=None,
433
- # controlnet_conditioning_scale=0.7,
434
- # guidance_scale=7.5,
435
- # )
436
-
437
- # save_cropped(images, paths.output_path)
438
-
439
-
440
- # def set_seed(seed: int):
441
- # if seed is None or seed < 0:
442
- # return
443
- # np.random.seed(seed)
444
- # torch.manual_seed(seed)
445
- # if torch.cuda.is_available():
446
- # torch.cuda.manual_seed_all(seed)
447
-
448
-
449
- # def infer_web(person_fp, sketch_fp, style_fp, prompt, steps, seed):
450
- # if person_fp is None or sketch_fp is None or style_fp is None:
451
- # raise gr.Error("person / sketch / style 이미지를 모두 업로드해야 합니다.")
452
-
453
- # set_seed(int(seed) if seed is not None else -1)
454
-
455
- # tmp_dir = tempfile.mkdtemp(prefix="vista_demo_")
456
- # out_path = os.path.join(tmp_dir, "result.png")
457
-
458
- # paths = Paths(
459
- # person_path=person_fp,
460
- # depth_path=sketch_fp,
461
- # style_path=style_fp,
462
- # output_path=out_path,
463
- # )
464
- # run_one(paths, prompt=prompt, steps=int(steps))
465
-
466
- # out_img = Image.open(out_path).convert("RGB")
467
- # return out_img, out_path
468
-
469
-
470
- # with gr.Blocks(title="VISTA Demo (HF Spaces)") as demo:
471
- # gr.Markdown("## VISTA Demo\nperson / sketch(guide) / style 입력으로 결과를 생성합니다.")
472
-
473
- # with gr.Row():
474
- # person_in = gr.Image(label="Person Image", type="filepath")
475
- # sketch_in = gr.Image(label="Sketch / Guide (depth_path)", type="filepath")
476
- # style_in = gr.Image(label="Style Image", type="filepath")
477
-
478
- # with gr.Row():
479
- # prompt_in = gr.Textbox(label="Prompt", value="upper garment", lines=2)
480
- # steps_in = gr.Slider(1, 80, value=DEFAULT_STEPS, step=1, label="Steps")
481
- # seed_in = gr.Number(label="Seed (-1=random)", value=-1, precision=0)
482
-
483
- # run_btn = gr.Button("Run")
484
- # out_img = gr.Image(label="Output", type="pil")
485
- # out_file = gr.File(label="Download result.png")
486
-
487
- # run_btn.click(
488
- # fn=infer_web,
489
- # inputs=[person_in, sketch_in, style_in, prompt_in, steps_in, seed_in],
490
- # outputs=[out_img, out_file],
491
- # )
492
-
493
- # demo.queue()
494
- # if __name__ == "__main__":
495
- # demo.launch(server_name="0.0.0.0", server_port=7860)
496
-
497
  import os
498
  import sys
499
 
@@ -594,6 +98,18 @@ def _imread_or_raise(path: str, flag=cv2.IMREAD_COLOR):
594
  raise FileNotFoundError(f"cv2.imread failed: {path} (exists={os.path.exists(path)})")
595
  return img
596
 
 
 
 
 
 
 
 
 
 
 
 
 
597
 
598
  def compute_hw_from_person(person_path: str):
599
  img = _imread_or_raise(person_path)
@@ -824,6 +340,25 @@ def run_one(paths: Paths, prompt: str, steps: int = DEFAULT_STEPS):
824
  depth_map = make_depth(paths.depth_path)
825
 
826
  garment_pil = person_pil.copy()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
827
 
828
  gm = np.array(parsing_img.convert("L"), dtype=np.uint8)
829
  gm = cv2.resize(gm, (W, H), interpolation=cv2.INTER_AREA)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import sys
3
 
 
98
  raise FileNotFoundError(f"cv2.imread failed: {path} (exists={os.path.exists(path)})")
99
  return img
100
 
101
+ def apply_parsing_white_mask_to_person_cv2(
102
+ person_pil: Image.Image,
103
+ parsing_img: Image.Image
104
+ ) -> np.ndarray:
105
+ person_rgb = np.array(person_pil.convert("RGB"), dtype=np.uint8)
106
+ mask = np.array(parsing_img.convert("L"), dtype=np.uint8)
107
+ white_mask = mask == 255
108
+ result_rgb = np.full_like(person_rgb, 255, dtype=np.uint8)
109
+ result_rgb[white_mask] = person_rgb[white_mask]
110
+ result_bgr = cv2.cvtColor(result_rgb, cv2.COLOR_RGB2BGR)
111
+ return result_bgr
112
+
113
 
114
  def compute_hw_from_person(person_path: str):
115
  img = _imread_or_raise(person_path)
 
340
  depth_map = make_depth(paths.depth_path)
341
 
342
  garment_pil = person_pil.copy()
343
+
344
+ garment_ = apply_parsing_white_mask_to_person_cv2(
345
+ garment_pil,
346
+ parsing_img
347
+ )
348
+
349
+ garment_rgb = cv2.cvtColor(garment_, cv2.COLOR_BGR2RGB)
350
+
351
+ # ✅ (중요) garment_는 원본 person 크기일 수 있으니 전역 (W,H)로 맞춘 뒤 padding
352
+ garment_rgb = cv2.resize(garment_rgb, (W, H), interpolation=cv2.INTER_AREA)
353
+
354
+ garment_rgb = cv2.copyMakeBorder(
355
+ garment_rgb,
356
+ top=0, bottom=0,
357
+ left=padding, right=padding,
358
+ borderType=cv2.BORDER_CONSTANT,
359
+ value=[255, 255, 255],
360
+ )
361
+ garment_pil = Image.fromarray(garment_rgb)
362
 
363
  gm = np.array(parsing_img.convert("L"), dtype=np.uint8)
364
  gm = cv2.resize(gm, (W, H), interpolation=cv2.INTER_AREA)