Ken2707 commited on
Commit
115c4e7
·
verified ·
1 Parent(s): ccaccb1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +497 -141
app.py CHANGED
@@ -9,7 +9,8 @@ import spaces # must come before any CUDA-touching import
9
  import torch
10
  torch.jit.script = lambda f: f # must be patched before detectron2 imports
11
 
12
- # Install detectron2 from source for current Python / torch
 
13
  try:
14
  import detectron2 # noqa: F401
15
  except ImportError:
@@ -32,60 +33,80 @@ from utils import init_weight_dtype, resize_and_crop, resize_and_padding
32
 
33
 
34
  def parse_args():
35
- parser = argparse.ArgumentParser(description="CatVTON Gradio App")
36
  parser.add_argument(
37
  "--base_model_path",
38
  type=str,
39
  default="booksforcharlie/stable-diffusion-inpainting",
40
- help="Path to base SD model",
 
 
41
  )
42
  parser.add_argument(
43
  "--p2p_base_model_path",
44
  type=str,
45
  default="timbrooks/instruct-pix2pix",
46
- help="Path to base InstructPix2Pix model",
 
 
47
  )
48
  parser.add_argument(
49
  "--resume_path",
50
  type=str,
51
  default="zhengchong/CatVTON",
52
- help="Path to CatVTON checkpoint",
 
 
53
  )
54
  parser.add_argument(
55
  "--output_dir",
56
  type=str,
57
  default="resource/demo/output",
58
- help="Output directory",
59
  )
 
60
  parser.add_argument(
61
  "--width",
62
  type=int,
63
  default=768,
64
- help="Image width",
 
 
 
65
  )
66
  parser.add_argument(
67
  "--height",
68
  type=int,
69
  default=1024,
70
- help="Image height",
 
 
 
71
  )
72
  parser.add_argument(
73
  "--repaint",
74
  action="store_true",
75
- help="Whether to repaint result image with original background."
76
  )
77
  parser.add_argument(
78
  "--allow_tf32",
79
  action="store_true",
80
  default=True,
81
- help="Allow TF32 on Ampere GPUs",
 
 
 
82
  )
83
  parser.add_argument(
84
  "--mixed_precision",
85
  type=str,
86
  default="bf16",
87
  choices=["no", "fp16", "bf16"],
88
- help="Mixed precision mode",
 
 
 
 
89
  )
90
 
91
  args, _unknown = parser.parse_known_args([])
@@ -95,63 +116,23 @@ def parse_args():
95
 
96
  return args
97
 
98
-
99
  def image_grid(imgs, rows, cols):
100
  assert len(imgs) == rows * cols
 
101
  w, h = imgs[0].size
102
  grid = Image.new("RGB", size=(cols * w, rows * h))
 
103
  for i, img in enumerate(imgs):
104
  grid.paste(img, box=(i % cols * w, i // cols * h))
105
  return grid
106
 
107
 
108
- # Extractor Universal untuk menangani Gradio Image / ImageEditor / Dictionary / String / Array
109
- def extract_pil_image(data):
110
- if data is None:
111
- return None
112
-
113
- if isinstance(data, Image.Image):
114
- return data.convert("RGB")
115
-
116
- if isinstance(data, str):
117
- if data.startswith("http://") or data.startswith("https://"):
118
- import requests
119
- from io import BytesIO
120
- res = requests.get(data)
121
- return Image.open(BytesIO(res.content)).convert("RGB")
122
- try:
123
- return Image.open(data).convert("RGB")
124
- except Exception as e:
125
- print(f"[DEBUG] Gagal Buka Path String: {e}")
126
- return None
127
-
128
- if hasattr(data, "shape"):
129
- return Image.fromarray(data).convert("RGB")
130
-
131
- if isinstance(data, (list, tuple)) and len(data) > 0:
132
- return extract_pil_image(data[0])
133
-
134
- if isinstance(data, dict):
135
- for key in ["background", "composite", "image", "path", "url", "file", "value"]:
136
- val = data.get(key)
137
- if val is not None:
138
- img = extract_pil_image(val)
139
- if img is not None:
140
- return img
141
- for k, v in data.items():
142
- if k != "layers" and v is not None:
143
- img = extract_pil_image(v)
144
- if img is not None:
145
- return img
146
-
147
- return None
148
-
149
-
150
  args = parse_args()
151
 
152
- # 1. Mask-based CatVTON (SD 1.5)
153
  catvton_repo = "zhengchong/CatVTON"
154
  repo_path = snapshot_download(repo_id=catvton_repo)
 
155
  pipeline = CatVTONPipeline(
156
  base_ckpt=args.base_model_path,
157
  attn_ckpt=repo_path,
@@ -160,7 +141,7 @@ pipeline = CatVTONPipeline(
160
  use_tf32=args.allow_tf32,
161
  device='cuda'
162
  )
163
-
164
  mask_processor = VaeImageProcessor(vae_scale_factor=8, do_normalize=False, do_binarize=True, do_convert_grayscale=True)
165
  automasker = AutoMasker(
166
  densepose_ckpt=os.path.join(repo_path, "DensePose"),
@@ -168,11 +149,14 @@ automasker = AutoMasker(
168
  device='cuda',
169
  )
170
 
171
- # 2. Flux-based CatVTON
 
172
  access_token = os.getenv("HUGGING_FACE_HUB_TOKEN")
173
  flux_repo = "black-forest-labs/FLUX.1-Fill-dev"
174
  pipeline_flux = FluxTryOnPipeline.from_pretrained(flux_repo, token=access_token)
175
-
 
 
176
  _lora_dir = os.path.join(repo_path, "flux-lora")
177
  try:
178
  pipeline_flux.load_lora_weights(
@@ -185,6 +169,7 @@ except AttributeError:
185
  _lora_dir, weight_name='pytorch_lora_weights.safetensors'
186
  )
187
  state_dict = _ret[0] if isinstance(_ret, tuple) else _ret
 
188
  transformer_sd = {
189
  k.removeprefix("transformer."): v
190
  for k, v in state_dict.items()
@@ -198,12 +183,14 @@ except AttributeError:
198
  transformer=pipeline_flux.transformer,
199
  )
200
  except TypeError:
 
201
  FluxLoraLoaderMixin.load_lora_into_transformer(
202
  transformer_sd, transformer=pipeline_flux.transformer,
203
  )
204
  pipeline_flux.to("cuda", init_weight_dtype(args.mixed_precision))
205
 
206
- # 3. Mask-free CatVTON
 
207
  catvton_mf_repo = "zhengchong/CatVTON-MaskFree"
208
  repo_path_mf = snapshot_download(repo_id=catvton_mf_repo, token=access_token)
209
  pipeline_p2p = CatVTONPix2PixPipeline(
@@ -226,12 +213,70 @@ def submit_function(
226
  seed,
227
  show_type
228
  ):
 
 
 
 
 
 
 
229
  if person_image is None or cloth_image is None:
230
  raise gr.Error("Silakan unggah foto orang dan foto pakaian terlebih dahulu.")
231
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  person_image_pil = extract_pil_image(person_image)
233
  cloth_image_pil = extract_pil_image(cloth_image)
234
 
 
235
  mask_pil = None
236
  if isinstance(person_image, dict) and "layers" in person_image:
237
  layers = person_image.get("layers", [])
@@ -240,32 +285,43 @@ def submit_function(
240
  if mask_pil:
241
  mask_pil = mask_pil.convert("L")
242
 
243
- if person_image_pil is None or cloth_image_pil is None:
244
- raise gr.Error("Foto orang atau pakaian tidak terdeteksi/gagal dimuat.")
 
 
 
245
 
246
  person_image = person_image_pil
247
  cloth_image = cloth_image_pil
248
  mask = mask_pil
249
 
 
250
  tmp_folder = args.output_dir
251
  date_str = datetime.now().strftime("%Y%m%d%H%M%S")
252
  result_save_path = os.path.join(tmp_folder, date_str[:8], date_str[8:] + ".png")
253
- os.makedirs(os.path.join(tmp_folder, date_str[:8]), exist_ok=True)
 
254
 
255
  generator = None
256
  if seed != -1:
257
  generator = torch.Generator(device='cuda').manual_seed(seed)
258
 
 
259
  person_image = resize_and_crop(person_image, (args.width, args.height))
260
  cloth_image = resize_and_padding(cloth_image, (args.width, args.height))
261
 
 
262
  if mask is not None:
263
  mask = resize_and_crop(mask, (args.width, args.height))
264
  else:
265
- mask = automasker(person_image, cloth_type)['mask']
 
 
 
266
 
267
  mask = mask_processor.blur(mask, blur_factor=9)
268
 
 
269
  result_image = pipeline(
270
  image=person_image,
271
  condition_image=cloth_image,
@@ -275,6 +331,7 @@ def submit_function(
275
  generator=generator
276
  )[0]
277
 
 
278
  masked_person = vis_mask(person_image, mask)
279
  save_result_image = image_grid([person_image, masked_person, cloth_image, result_image], 1, 4)
280
  save_result_image.save(result_save_path)
@@ -294,34 +351,32 @@ def submit_function(
294
  new_result_image.paste(conditions, (0, 0))
295
  new_result_image.paste(result_image, (condition_width + 5, 0))
296
  return new_result_image
297
-
298
-
299
  @spaces.GPU(duration=120)
300
  def submit_function_p2p(
301
  person_image,
302
  cloth_image,
303
  num_inference_steps,
304
  guidance_scale,
305
- seed
306
- ):
307
- person_image = extract_pil_image(person_image)
308
- cloth_image = extract_pil_image(cloth_image)
309
-
310
- if person_image is None or cloth_image is None:
311
- raise gr.Error("Gagal memuat gambar input.")
312
 
313
  tmp_folder = args.output_dir
314
  date_str = datetime.now().strftime("%Y%m%d%H%M%S")
315
  result_save_path = os.path.join(tmp_folder, date_str[:8], date_str[8:] + ".png")
316
- os.makedirs(os.path.join(tmp_folder, date_str[:8]), exist_ok=True)
 
317
 
318
  generator = None
319
  if seed != -1:
320
  generator = torch.Generator(device='cuda').manual_seed(seed)
321
 
 
 
322
  person_image = resize_and_crop(person_image, (args.width, args.height))
323
  cloth_image = resize_and_padding(cloth_image, (args.width, args.height))
324
 
 
325
  try:
326
  result_image = pipeline_p2p(
327
  image=person_image,
@@ -331,13 +386,15 @@ def submit_function_p2p(
331
  generator=generator
332
  )[0]
333
  except Exception as e:
334
- raise gr.Error(f"Terjadi kesalahan saat inferensi: {e}")
 
 
335
 
 
336
  save_result_image = image_grid([person_image, cloth_image, result_image], 1, 3)
337
  save_result_image.save(result_save_path)
338
  return result_image
339
 
340
-
341
  @spaces.GPU(duration=120)
342
  def submit_function_flux(
343
  person_image,
@@ -348,44 +405,41 @@ def submit_function_flux(
348
  seed,
349
  show_type
350
  ):
351
- person_image_pil = extract_pil_image(person_image)
352
- cloth_image_pil = extract_pil_image(cloth_image)
353
-
354
- mask_pil = None
355
- if isinstance(person_image, dict) and "layers" in person_image:
356
- layers = person_image.get("layers", [])
357
- if isinstance(layers, list) and len(layers) > 0 and layers[0] is not None:
358
- mask_pil = extract_pil_image(layers[0])
359
- if mask_pil:
360
- mask_pil = mask_pil.convert("L")
361
- mask_arr = np.array(mask_pil)
362
- if len(np.unique(mask_arr)) > 1:
363
- mask_arr[mask_arr > 0] = 255
364
- mask_pil = Image.fromarray(mask_arr)
365
- else:
366
- mask_pil = None
367
-
368
- if person_image_pil is None or cloth_image_pil is None:
369
- raise gr.Error("Gambar orang atau pakaian tidak valid.")
370
 
371
- person_image = person_image_pil
372
- cloth_image = cloth_image_pil
373
- mask = mask_pil
 
 
 
 
 
 
374
 
 
375
  generator = None
376
  if seed != -1:
377
  generator = torch.Generator(device='cuda').manual_seed(seed)
378
 
 
 
 
 
 
379
  person_image = resize_and_crop(person_image, (args.width, args.height))
380
  cloth_image = resize_and_padding(cloth_image, (args.width, args.height))
381
 
 
382
  if mask is not None:
383
  mask = resize_and_crop(mask, (args.width, args.height))
384
  else:
385
- mask = automasker(person_image, cloth_type)['mask']
386
-
 
 
387
  mask = mask_processor.blur(mask, blur_factor=9)
388
 
 
389
  result_image = pipeline_flux(
390
  image=person_image,
391
  condition_image=cloth_image,
@@ -397,8 +451,10 @@ def submit_function_flux(
397
  generator=generator
398
  ).images[0]
399
 
 
400
  masked_person = vis_mask(person_image, mask)
401
 
 
402
  if show_type == "result only":
403
  return result_image
404
  else:
@@ -423,113 +479,413 @@ def person_example_fn(image_path):
423
 
424
  HEADER = """
425
  <h1 style="text-align: center;"> 🐈 CatVTON: Concatenation Is All You Need for Virtual Try-On with Diffusion Models </h1>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
426
  """
427
 
428
  def app_gradio():
429
  with gr.Blocks(title="CatVTON") as demo:
430
  gr.Markdown(HEADER)
431
-
432
- # TAB 1: Mask-based SD 1.5
433
  with gr.Tab("Mask-based & SD1.5"):
434
  with gr.Row():
435
  with gr.Column(scale=1, min_width=350):
436
- image_path = gr.Image(type="filepath", interactive=True, visible=False)
437
- person_image = gr.ImageEditor(interactive=True, label="Person Image", type="filepath")
 
 
 
 
 
 
 
 
438
  with gr.Row():
439
  with gr.Column(scale=1, min_width=230):
440
- cloth_image = gr.Image(interactive=True, label="Condition Image", type="filepath")
 
 
441
  with gr.Column(scale=1, min_width=120):
 
 
 
442
  cloth_type = gr.Radio(
443
  label="Try-On Cloth Type",
444
  choices=["upper", "lower", "overall"],
445
  value="upper",
446
  )
 
 
447
  submit = gr.Button("Submit")
 
 
 
 
 
 
 
448
  with gr.Accordion("Advanced Options", open=False):
449
- num_inference_steps = gr.Slider(label="Inference Step", minimum=10, maximum=100, step=5, value=50)
450
- guidance_scale = gr.Slider(label="CFG Strength", minimum=0.0, maximum=7.5, step=0.5, value=2.5)
451
- seed = gr.Slider(label="Seed", minimum=-1, maximum=10000, step=1, value=42)
 
 
 
 
 
 
 
 
452
  show_type = gr.Radio(
453
  label="Show Type",
454
  choices=["result only", "input & result", "input & mask & result"],
455
  value="input & mask & result",
456
  )
 
457
  with gr.Column(scale=2, min_width=500):
458
  result_image = gr.Image(interactive=False, label="Result")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
459
 
460
- image_path.change(person_example_fn, inputs=image_path, outputs=person_image)
461
  submit.click(
462
  submit_function,
463
- [person_image, cloth_image, cloth_type, num_inference_steps, guidance_scale, seed, show_type],
 
 
 
 
 
 
 
 
464
  result_image,
465
  )
466
 
467
- # TAB 2: Mask-based FLUX.1 Fill
468
  with gr.Tab("Mask-based & Flux.1 Fill Dev"):
469
  with gr.Row():
470
  with gr.Column(scale=1, min_width=350):
471
- image_path_flux = gr.Image(type="filepath", interactive=True, visible=False)
472
- person_image_flux = gr.ImageEditor(interactive=True, label="Person Image", type="filepath")
 
 
 
 
 
 
 
 
473
  with gr.Row():
474
  with gr.Column(scale=1, min_width=230):
475
- cloth_image_flux = gr.Image(interactive=True, label="Condition Image", type="filepath")
 
 
476
  with gr.Column(scale=1, min_width=120):
477
- cloth_type_flux = gr.Radio(
 
 
 
478
  label="Try-On Cloth Type",
479
  choices=["upper", "lower", "overall"],
480
  value="upper",
481
  )
 
482
  submit_flux = gr.Button("Submit")
 
 
 
 
483
  with gr.Accordion("Advanced Options", open=False):
484
- num_inference_steps_flux = gr.Slider(label="Inference Step", minimum=10, maximum=100, step=5, value=50)
485
- guidance_scale_flux = gr.Slider(label="CFG Strength", minimum=0.0, maximum=50, step=0.5, value=30)
486
- seed_flux = gr.Slider(label="Seed", minimum=-1, maximum=10000, step=1, value=42)
487
- show_type_flux = gr.Radio(
 
 
 
 
 
 
 
 
488
  label="Show Type",
489
  choices=["result only", "input & result", "input & mask & result"],
490
  value="input & mask & result",
491
  )
 
492
  with gr.Column(scale=2, min_width=500):
493
  result_image_flux = gr.Image(interactive=False, label="Result")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
494
 
495
- image_path_flux.change(person_example_fn, inputs=image_path_flux, outputs=person_image_flux)
496
  submit_flux.click(
497
  submit_function_flux,
498
- [
499
- person_image_flux,
500
- cloth_image_flux,
501
- cloth_type_flux,
502
- num_inference_steps_flux,
503
- guidance_scale_flux,
504
- seed_flux,
505
- show_type_flux,
506
- ],
507
  result_image_flux,
508
  )
509
-
510
- # TAB 3: Mask-free CatVTON
511
- with gr.Tab("Mask-free & Pix2Pix"):
512
  with gr.Row():
513
  with gr.Column(scale=1, min_width=350):
514
- person_image_p2p = gr.Image(interactive=True, label="Person Image", type="filepath")
515
- cloth_image_p2p = gr.Image(interactive=True, label="Condition Image", type="filepath")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
516
  submit_p2p = gr.Button("Submit")
 
 
 
 
 
 
 
517
  with gr.Accordion("Advanced Options", open=False):
518
- num_inference_steps_p2p = gr.Slider(label="Inference Step", minimum=10, maximum=100, step=5, value=50)
519
- guidance_scale_p2p = gr.Slider(label="CFG Strength", minimum=0.0, maximum=7.5, step=0.5, value=2.5)
520
- seed_p2p = gr.Slider(label="Seed", minimum=-1, maximum=10000, step=1, value=42)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
521
  with gr.Column(scale=2, min_width=500):
522
  result_image_p2p = gr.Image(interactive=False, label="Result")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
523
 
524
  submit_p2p.click(
525
  submit_function_p2p,
526
- [person_image_p2p, cloth_image_p2p, num_inference_steps_p2p, guidance_scale_p2p, seed_p2p],
 
 
 
 
 
527
  result_image_p2p,
528
  )
529
-
530
- return demo
531
 
532
 
533
  if __name__ == "__main__":
534
- demo = app_gradio()
535
- demo.queue().launch()
 
9
  import torch
10
  torch.jit.script = lambda f: f # must be patched before detectron2 imports
11
 
12
+ # Install detectron2 from source for current Python / torch (the bundled
13
+ # detectron2/_C.cpython-39 .so doesn't work on the Blackwell container).
14
  try:
15
  import detectron2 # noqa: F401
16
  except ImportError:
 
33
 
34
 
35
  def parse_args():
36
+ parser = argparse.ArgumentParser(description="Simple example of a training script.")
37
  parser.add_argument(
38
  "--base_model_path",
39
  type=str,
40
  default="booksforcharlie/stable-diffusion-inpainting",
41
+ help=(
42
+ "The path to the base model to use for evaluation. This can be a local path or a model identifier from the Model Hub."
43
+ ),
44
  )
45
  parser.add_argument(
46
  "--p2p_base_model_path",
47
  type=str,
48
  default="timbrooks/instruct-pix2pix",
49
+ help=(
50
+ "The path to the base model to use for evaluation. This can be a local path or a model identifier from the Model Hub."
51
+ ),
52
  )
53
  parser.add_argument(
54
  "--resume_path",
55
  type=str,
56
  default="zhengchong/CatVTON",
57
+ help=(
58
+ "The Path to the checkpoint of trained tryon model."
59
+ ),
60
  )
61
  parser.add_argument(
62
  "--output_dir",
63
  type=str,
64
  default="resource/demo/output",
65
+ help="The output directory where the model predictions will be written.",
66
  )
67
+
68
  parser.add_argument(
69
  "--width",
70
  type=int,
71
  default=768,
72
+ help=(
73
+ "The resolution for input images, all the images in the train/validation dataset will be resized to this"
74
+ " resolution"
75
+ ),
76
  )
77
  parser.add_argument(
78
  "--height",
79
  type=int,
80
  default=1024,
81
+ help=(
82
+ "The resolution for input images, all the images in the train/validation dataset will be resized to this"
83
+ " resolution"
84
+ ),
85
  )
86
  parser.add_argument(
87
  "--repaint",
88
  action="store_true",
89
+ help="Whether to repaint the result image with the original background."
90
  )
91
  parser.add_argument(
92
  "--allow_tf32",
93
  action="store_true",
94
  default=True,
95
+ help=(
96
+ "Whether or not to allow TF32 on Ampere GPUs. Can be used to speed up training. For more information, see"
97
+ " https://pytorch.org/docs/stable/notes/cuda.html#tensorfloat-32-tf32-on-ampere-devices"
98
+ ),
99
  )
100
  parser.add_argument(
101
  "--mixed_precision",
102
  type=str,
103
  default="bf16",
104
  choices=["no", "fp16", "bf16"],
105
+ help=(
106
+ "Whether to use mixed precision. Choose between fp16 and bf16 (bfloat16). Bf16 requires PyTorch >="
107
+ " 1.10.and an Nvidia Ampere GPU. Default to the value of accelerate config of the current system or the"
108
+ " flag passed with the `accelerate.launch` command. Use this argument to override the accelerate config."
109
+ ),
110
  )
111
 
112
  args, _unknown = parser.parse_known_args([])
 
116
 
117
  return args
118
 
 
119
  def image_grid(imgs, rows, cols):
120
  assert len(imgs) == rows * cols
121
+
122
  w, h = imgs[0].size
123
  grid = Image.new("RGB", size=(cols * w, rows * h))
124
+
125
  for i, img in enumerate(imgs):
126
  grid.paste(img, box=(i % cols * w, i // cols * h))
127
  return grid
128
 
129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  args = parse_args()
131
 
132
+ # Mask-based CatVTON
133
  catvton_repo = "zhengchong/CatVTON"
134
  repo_path = snapshot_download(repo_id=catvton_repo)
135
+ # Pipeline
136
  pipeline = CatVTONPipeline(
137
  base_ckpt=args.base_model_path,
138
  attn_ckpt=repo_path,
 
141
  use_tf32=args.allow_tf32,
142
  device='cuda'
143
  )
144
+ # AutoMasker
145
  mask_processor = VaeImageProcessor(vae_scale_factor=8, do_normalize=False, do_binarize=True, do_convert_grayscale=True)
146
  automasker = AutoMasker(
147
  densepose_ckpt=os.path.join(repo_path, "DensePose"),
 
149
  device='cuda',
150
  )
151
 
152
+
153
+ # Flux-based CatVTON
154
  access_token = os.getenv("HUGGING_FACE_HUB_TOKEN")
155
  flux_repo = "black-forest-labs/FLUX.1-Fill-dev"
156
  pipeline_flux = FluxTryOnPipeline.from_pretrained(flux_repo, token=access_token)
157
+ # The custom FluxTryOnPipeline drops the text encoder, but `load_lora_weights`
158
+ # tries to also load text-encoder LoRA modules. Bypass it by loading the LoRA
159
+ # state dict directly into the transformer.
160
  _lora_dir = os.path.join(repo_path, "flux-lora")
161
  try:
162
  pipeline_flux.load_lora_weights(
 
169
  _lora_dir, weight_name='pytorch_lora_weights.safetensors'
170
  )
171
  state_dict = _ret[0] if isinstance(_ret, tuple) else _ret
172
+ # keep only transformer LoRA tensors
173
  transformer_sd = {
174
  k.removeprefix("transformer."): v
175
  for k, v in state_dict.items()
 
183
  transformer=pipeline_flux.transformer,
184
  )
185
  except TypeError:
186
+ # newer signature drops network_alphas
187
  FluxLoraLoaderMixin.load_lora_into_transformer(
188
  transformer_sd, transformer=pipeline_flux.transformer,
189
  )
190
  pipeline_flux.to("cuda", init_weight_dtype(args.mixed_precision))
191
 
192
+
193
+ # Mask-free CatVTON
194
  catvton_mf_repo = "zhengchong/CatVTON-MaskFree"
195
  repo_path_mf = snapshot_download(repo_id=catvton_mf_repo, token=access_token)
196
  pipeline_p2p = CatVTONPix2PixPipeline(
 
213
  seed,
214
  show_type
215
  ):
216
+ # 1. PRINT DEBUGGING (Bisa dilihat di tab LOGS Hugging Face Space)
217
+ print("=" * 40)
218
+ print(f"[DEBUG] person_image Type : {type(person_image)}")
219
+ print(f"[DEBUG] person_image Content: {person_image}")
220
+ print(f"[DEBUG] cloth_image Type : {type(cloth_image)}")
221
+ print("=" * 40)
222
+
223
  if person_image is None or cloth_image is None:
224
  raise gr.Error("Silakan unggah foto orang dan foto pakaian terlebih dahulu.")
225
 
226
+ # 2. Extractor Universal: Otomatis membongkar List, Dict, Path, URL, Bytes, Numpy Array
227
+ def extract_pil_image(data):
228
+ if data is None:
229
+ return None
230
+
231
+ # Jika sudah PIL Image
232
+ if isinstance(data, Image.Image):
233
+ return data.convert("RGB")
234
+
235
+ # Jika berupa String (Local Path atau URL)
236
+ if isinstance(data, str):
237
+ if data.startswith("http://") or data.startswith("https://"):
238
+ import requests
239
+ from io import BytesIO
240
+ res = requests.get(data)
241
+ return Image.open(BytesIO(res.content)).convert("RGB")
242
+ try:
243
+ return Image.open(data).convert("RGB")
244
+ except Exception as e:
245
+ print(f"[DEBUG] Gagal Buka Path String: {e}")
246
+ return None
247
+
248
+ # Jika berupa Numpy Array
249
+ if hasattr(data, "shape"):
250
+ return Image.fromarray(data).convert("RGB")
251
+
252
+ # Jika data terbungkus dalam List / Tuple
253
+ if isinstance(data, (list, tuple)) and len(data) > 0:
254
+ return extract_pil_image(data[0])
255
+
256
+ # Jika berupa Dictionary (Gradio ImageEditor / API payload)
257
+ if isinstance(data, dict):
258
+ # Cek key standar Gradio berurutan
259
+ for key in ["background", "composite", "image", "path", "url", "file", "value"]:
260
+ val = data.get(key)
261
+ if val is not None:
262
+ img = extract_pil_image(val)
263
+ if img is not None:
264
+ return img
265
+
266
+ # Fallback: Cari value pertama di dict yang bukan layer mask
267
+ for k, v in data.items():
268
+ if k != "layers" and v is not None:
269
+ img = extract_pil_image(v)
270
+ if img is not None:
271
+ return img
272
+
273
+ return None
274
+
275
+ # Ekstraksi foto orang & pakaian
276
  person_image_pil = extract_pil_image(person_image)
277
  cloth_image_pil = extract_pil_image(cloth_image)
278
 
279
+ # Ekstraksi mask manual (jika ada coretan di ImageEditor)
280
  mask_pil = None
281
  if isinstance(person_image, dict) and "layers" in person_image:
282
  layers = person_image.get("layers", [])
 
285
  if mask_pil:
286
  mask_pil = mask_pil.convert("L")
287
 
288
+ # Validasi Hasil
289
+ if person_image_pil is None:
290
+ raise gr.Error("Foto orang tidak terdeteksi/gagal dimuat. Cek tab Logs di Space untuk detail data.")
291
+ if cloth_image_pil is None:
292
+ raise gr.Error("Foto pakaian tidak terdeteksi/gagal dimuat. Cek tab Logs di Space untuk detail data.")
293
 
294
  person_image = person_image_pil
295
  cloth_image = cloth_image_pil
296
  mask = mask_pil
297
 
298
+ # Direktori penyimpanan sementara
299
  tmp_folder = args.output_dir
300
  date_str = datetime.now().strftime("%Y%m%d%H%M%S")
301
  result_save_path = os.path.join(tmp_folder, date_str[:8], date_str[8:] + ".png")
302
+ if not os.path.exists(os.path.join(tmp_folder, date_str[:8])):
303
+ os.makedirs(os.path.join(tmp_folder, date_str[:8]))
304
 
305
  generator = None
306
  if seed != -1:
307
  generator = torch.Generator(device='cuda').manual_seed(seed)
308
 
309
+ # Resize dan Padding
310
  person_image = resize_and_crop(person_image, (args.width, args.height))
311
  cloth_image = resize_and_padding(cloth_image, (args.width, args.height))
312
 
313
+ # Process mask (Gunakan automasker jika tidak ada coretan manual)
314
  if mask is not None:
315
  mask = resize_and_crop(mask, (args.width, args.height))
316
  else:
317
+ mask = automasker(
318
+ person_image,
319
+ cloth_type
320
+ )['mask']
321
 
322
  mask = mask_processor.blur(mask, blur_factor=9)
323
 
324
+ # Inference AI Model
325
  result_image = pipeline(
326
  image=person_image,
327
  condition_image=cloth_image,
 
331
  generator=generator
332
  )[0]
333
 
334
+ # Post-process & Format Output
335
  masked_person = vis_mask(person_image, mask)
336
  save_result_image = image_grid([person_image, masked_person, cloth_image, result_image], 1, 4)
337
  save_result_image.save(result_save_path)
 
351
  new_result_image.paste(conditions, (0, 0))
352
  new_result_image.paste(result_image, (condition_width + 5, 0))
353
  return new_result_image
354
+
 
355
  @spaces.GPU(duration=120)
356
  def submit_function_p2p(
357
  person_image,
358
  cloth_image,
359
  num_inference_steps,
360
  guidance_scale,
361
+ seed):
362
+ person_image= person_image["background"]
 
 
 
 
 
363
 
364
  tmp_folder = args.output_dir
365
  date_str = datetime.now().strftime("%Y%m%d%H%M%S")
366
  result_save_path = os.path.join(tmp_folder, date_str[:8], date_str[8:] + ".png")
367
+ if not os.path.exists(os.path.join(tmp_folder, date_str[:8])):
368
+ os.makedirs(os.path.join(tmp_folder, date_str[:8]))
369
 
370
  generator = None
371
  if seed != -1:
372
  generator = torch.Generator(device='cuda').manual_seed(seed)
373
 
374
+ person_image = Image.open(person_image).convert("RGB")
375
+ cloth_image = Image.open(cloth_image).convert("RGB")
376
  person_image = resize_and_crop(person_image, (args.width, args.height))
377
  cloth_image = resize_and_padding(cloth_image, (args.width, args.height))
378
 
379
+ # Inference
380
  try:
381
  result_image = pipeline_p2p(
382
  image=person_image,
 
386
  generator=generator
387
  )[0]
388
  except Exception as e:
389
+ raise gr.Error(
390
+ "An error occurred. Please try again later: {}".format(e)
391
+ )
392
 
393
+ # Post-process
394
  save_result_image = image_grid([person_image, cloth_image, result_image], 1, 3)
395
  save_result_image.save(result_save_path)
396
  return result_image
397
 
 
398
  @spaces.GPU(duration=120)
399
  def submit_function_flux(
400
  person_image,
 
405
  seed,
406
  show_type
407
  ):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
408
 
409
+ # Process image editor input
410
+ person_image, mask = person_image["background"], person_image["layers"][0]
411
+ mask = Image.open(mask).convert("L")
412
+ if len(np.unique(np.array(mask))) == 1:
413
+ mask = None
414
+ else:
415
+ mask = np.array(mask)
416
+ mask[mask > 0] = 255
417
+ mask = Image.fromarray(mask)
418
 
419
+ # Set random seed
420
  generator = None
421
  if seed != -1:
422
  generator = torch.Generator(device='cuda').manual_seed(seed)
423
 
424
+ # Process input images
425
+ person_image = Image.open(person_image).convert("RGB")
426
+ cloth_image = Image.open(cloth_image).convert("RGB")
427
+
428
+ # Adjust image sizes
429
  person_image = resize_and_crop(person_image, (args.width, args.height))
430
  cloth_image = resize_and_padding(cloth_image, (args.width, args.height))
431
 
432
+ # Process mask
433
  if mask is not None:
434
  mask = resize_and_crop(mask, (args.width, args.height))
435
  else:
436
+ mask = automasker(
437
+ person_image,
438
+ cloth_type
439
+ )['mask']
440
  mask = mask_processor.blur(mask, blur_factor=9)
441
 
442
+ # Inference
443
  result_image = pipeline_flux(
444
  image=person_image,
445
  condition_image=cloth_image,
 
451
  generator=generator
452
  ).images[0]
453
 
454
+ # Post-processing
455
  masked_person = vis_mask(person_image, mask)
456
 
457
+ # Return result based on show type
458
  if show_type == "result only":
459
  return result_image
460
  else:
 
479
 
480
  HEADER = """
481
  <h1 style="text-align: center;"> 🐈 CatVTON: Concatenation Is All You Need for Virtual Try-On with Diffusion Models </h1>
482
+ <div style="display: flex; justify-content: center; align-items: center;">
483
+ <a href="http://arxiv.org/abs/2407.15886" style="margin: 0 2px;">
484
+ <img src='https://img.shields.io/badge/arXiv-2407.15886-red?style=flat&logo=arXiv&logoColor=red' alt='arxiv'>
485
+ </a>
486
+ <a href='https://huggingface.co/zhengchong/CatVTON' style="margin: 0 2px;">
487
+ <img src='https://img.shields.io/badge/Hugging Face-ckpts-orange?style=flat&logo=HuggingFace&logoColor=orange' alt='huggingface'>
488
+ </a>
489
+ <a href="https://github.com/Zheng-Chong/CatVTON" style="margin: 0 2px;">
490
+ <img src='https://img.shields.io/badge/GitHub-Repo-blue?style=flat&logo=GitHub' alt='GitHub'>
491
+ </a>
492
+ <a href="http://120.76.142.206:8888" style="margin: 0 2px;">
493
+ <img src='https://img.shields.io/badge/Demo-Gradio-gold?style=flat&logo=Gradio&logoColor=red' alt='Demo'>
494
+ </a>
495
+ <a href="https://huggingface.co/spaces/zhengchong/CatVTON" style="margin: 0 2px;">
496
+ <img src='https://img.shields.io/badge/Space-ZeroGPU-orange?style=flat&logo=Gradio&logoColor=red' alt='Demo'>
497
+ </a>
498
+ <a href='https://zheng-chong.github.io/CatVTON/' style="margin: 0 2px;">
499
+ <img src='https://img.shields.io/badge/Webpage-Project-silver?style=flat&logo=&logoColor=orange' alt='webpage'>
500
+ </a>
501
+ <a href="https://github.com/Zheng-Chong/CatVTON/LICENCE" style="margin: 0 2px;">
502
+ <img src='https://img.shields.io/badge/License-CC BY--NC--SA--4.0-lightgreen?style=flat&logo=Lisence' alt='License'>
503
+ </a>
504
+ </div>
505
+ <br>
506
+ · This demo and our weights are only for Non-commercial Use. <br>
507
+ · Thanks to <a href="https://huggingface.co/zero-gpu-explorers">ZeroGPU</a> for providing A100 for our <a href="https://huggingface.co/spaces/zhengchong/CatVTON">HuggingFace Space</a>. <br>
508
+ · SafetyChecker is set to filter NSFW content, but it may block normal results too. Please adjust the <span>`seed`</span> for normal outcomes.<br>
509
  """
510
 
511
  def app_gradio():
512
  with gr.Blocks(title="CatVTON") as demo:
513
  gr.Markdown(HEADER)
 
 
514
  with gr.Tab("Mask-based & SD1.5"):
515
  with gr.Row():
516
  with gr.Column(scale=1, min_width=350):
517
+ with gr.Row():
518
+ image_path = gr.Image(
519
+ type="filepath",
520
+ interactive=True,
521
+ visible=False,
522
+ )
523
+ person_image = gr.ImageEditor(
524
+ interactive=True, label="Person Image", type="filepath"
525
+ )
526
+
527
  with gr.Row():
528
  with gr.Column(scale=1, min_width=230):
529
+ cloth_image = gr.Image(
530
+ interactive=True, label="Condition Image", type="filepath"
531
+ )
532
  with gr.Column(scale=1, min_width=120):
533
+ gr.Markdown(
534
+ '<span style="color: #808080; font-size: small;">Two ways to provide Mask:<br>1. Upload the person image and use the `🖌️` above to draw the Mask (higher priority)<br>2. Select the `Try-On Cloth Type` to generate automatically </span>'
535
+ )
536
  cloth_type = gr.Radio(
537
  label="Try-On Cloth Type",
538
  choices=["upper", "lower", "overall"],
539
  value="upper",
540
  )
541
+
542
+
543
  submit = gr.Button("Submit")
544
+ gr.Markdown(
545
+ '<center><span style="color: #FF0000">!!! Click only Once, Wait for Delay !!!</span></center>'
546
+ )
547
+
548
+ gr.Markdown(
549
+ '<span style="color: #808080; font-size: small;">Advanced options can adjust details:<br>1. `Inference Step` may enhance details;<br>2. `CFG` is highly correlated with saturation;<br>3. `Random seed` may improve pseudo-shadow.</span>'
550
+ )
551
  with gr.Accordion("Advanced Options", open=False):
552
+ num_inference_steps = gr.Slider(
553
+ label="Inference Step", minimum=10, maximum=100, step=5, value=50
554
+ )
555
+ # Guidence Scale
556
+ guidance_scale = gr.Slider(
557
+ label="CFG Strenth", minimum=0.0, maximum=7.5, step=0.5, value=2.5
558
+ )
559
+ # Random Seed
560
+ seed = gr.Slider(
561
+ label="Seed", minimum=-1, maximum=10000, step=1, value=42
562
+ )
563
  show_type = gr.Radio(
564
  label="Show Type",
565
  choices=["result only", "input & result", "input & mask & result"],
566
  value="input & mask & result",
567
  )
568
+
569
  with gr.Column(scale=2, min_width=500):
570
  result_image = gr.Image(interactive=False, label="Result")
571
+ with gr.Row():
572
+ # Photo Examples
573
+ root_path = "resource/demo/example"
574
+ with gr.Column():
575
+ men_exm = gr.Examples(
576
+ examples=[
577
+ os.path.join(root_path, "person", "men", _)
578
+ for _ in os.listdir(os.path.join(root_path, "person", "men"))
579
+ ],
580
+ examples_per_page=4,
581
+ inputs=image_path,
582
+ label="Person Examples ①",
583
+ )
584
+ women_exm = gr.Examples(
585
+ examples=[
586
+ os.path.join(root_path, "person", "women", _)
587
+ for _ in os.listdir(os.path.join(root_path, "person", "women"))
588
+ ],
589
+ examples_per_page=4,
590
+ inputs=image_path,
591
+ label="Person Examples ②",
592
+ )
593
+ gr.Markdown(
594
+ '<span style="color: #808080; font-size: small;">*Person examples come from the demos of <a href="https://huggingface.co/spaces/levihsu/OOTDiffusion">OOTDiffusion</a> and <a href="https://www.outfitanyone.org">OutfitAnyone</a>. </span>'
595
+ )
596
+ with gr.Column():
597
+ condition_upper_exm = gr.Examples(
598
+ examples=[
599
+ os.path.join(root_path, "condition", "upper", _)
600
+ for _ in os.listdir(os.path.join(root_path, "condition", "upper"))
601
+ ],
602
+ examples_per_page=4,
603
+ inputs=cloth_image,
604
+ label="Condition Upper Examples",
605
+ )
606
+ condition_overall_exm = gr.Examples(
607
+ examples=[
608
+ os.path.join(root_path, "condition", "overall", _)
609
+ for _ in os.listdir(os.path.join(root_path, "condition", "overall"))
610
+ ],
611
+ examples_per_page=4,
612
+ inputs=cloth_image,
613
+ label="Condition Overall Examples",
614
+ )
615
+ condition_person_exm = gr.Examples(
616
+ examples=[
617
+ os.path.join(root_path, "condition", "person", _)
618
+ for _ in os.listdir(os.path.join(root_path, "condition", "person"))
619
+ ],
620
+ examples_per_page=4,
621
+ inputs=cloth_image,
622
+ label="Condition Reference Person Examples",
623
+ )
624
+ gr.Markdown(
625
+ '<span style="color: #808080; font-size: small;">*Condition examples come from the Internet. </span>'
626
+ )
627
+
628
+ image_path.change(
629
+ person_example_fn, inputs=image_path, outputs=person_image
630
+ )
631
 
 
632
  submit.click(
633
  submit_function,
634
+ [
635
+ person_image,
636
+ cloth_image,
637
+ cloth_type,
638
+ num_inference_steps,
639
+ guidance_scale,
640
+ seed,
641
+ show_type,
642
+ ],
643
  result_image,
644
  )
645
 
 
646
  with gr.Tab("Mask-based & Flux.1 Fill Dev"):
647
  with gr.Row():
648
  with gr.Column(scale=1, min_width=350):
649
+ with gr.Row():
650
+ image_path_flux = gr.Image(
651
+ type="filepath",
652
+ interactive=True,
653
+ visible=False,
654
+ )
655
+ person_image_flux = gr.ImageEditor(
656
+ interactive=True, label="Person Image", type="filepath"
657
+ )
658
+
659
  with gr.Row():
660
  with gr.Column(scale=1, min_width=230):
661
+ cloth_image_flux = gr.Image(
662
+ interactive=True, label="Condition Image", type="filepath"
663
+ )
664
  with gr.Column(scale=1, min_width=120):
665
+ gr.Markdown(
666
+ '<span style="color: #808080; font-size: small;">Two ways to provide Mask:<br>1. Upload the person image and use the `🖌️` above to draw the Mask (higher priority)<br>2. Select the `Try-On Cloth Type` to generate automatically </span>'
667
+ )
668
+ cloth_type = gr.Radio(
669
  label="Try-On Cloth Type",
670
  choices=["upper", "lower", "overall"],
671
  value="upper",
672
  )
673
+
674
  submit_flux = gr.Button("Submit")
675
+ gr.Markdown(
676
+ '<center><span style="color: #FF0000">!!! Click only Once, Wait for Delay !!!</span></center>'
677
+ )
678
+
679
  with gr.Accordion("Advanced Options", open=False):
680
+ num_inference_steps_flux = gr.Slider(
681
+ label="Inference Step", minimum=10, maximum=100, step=5, value=50
682
+ )
683
+ # Guidence Scale
684
+ guidance_scale_flux = gr.Slider(
685
+ label="CFG Strenth", minimum=0.0, maximum=50, step=0.5, value=30
686
+ )
687
+ # Random Seed
688
+ seed_flux = gr.Slider(
689
+ label="Seed", minimum=-1, maximum=10000, step=1, value=42
690
+ )
691
+ show_type = gr.Radio(
692
  label="Show Type",
693
  choices=["result only", "input & result", "input & mask & result"],
694
  value="input & mask & result",
695
  )
696
+
697
  with gr.Column(scale=2, min_width=500):
698
  result_image_flux = gr.Image(interactive=False, label="Result")
699
+ with gr.Row():
700
+ # Photo Examples
701
+ root_path = "resource/demo/example"
702
+ with gr.Column():
703
+ gr.Examples(
704
+ examples=[
705
+ os.path.join(root_path, "person", "men", _)
706
+ for _ in os.listdir(os.path.join(root_path, "person", "men"))
707
+ ],
708
+ examples_per_page=4,
709
+ inputs=image_path_flux,
710
+ label="Person Examples ①",
711
+ )
712
+ gr.Examples(
713
+ examples=[
714
+ os.path.join(root_path, "person", "women", _)
715
+ for _ in os.listdir(os.path.join(root_path, "person", "women"))
716
+ ],
717
+ examples_per_page=4,
718
+ inputs=image_path_flux,
719
+ label="Person Examples ②",
720
+ )
721
+ gr.Markdown(
722
+ '<span style="color: #808080; font-size: small;">*Person examples come from the demos of <a href="https://huggingface.co/spaces/levihsu/OOTDiffusion">OOTDiffusion</a> and <a href="https://www.outfitanyone.org">OutfitAnyone</a>. </span>'
723
+ )
724
+ with gr.Column():
725
+ gr.Examples(
726
+ examples=[
727
+ os.path.join(root_path, "condition", "upper", _)
728
+ for _ in os.listdir(os.path.join(root_path, "condition", "upper"))
729
+ ],
730
+ examples_per_page=4,
731
+ inputs=cloth_image_flux,
732
+ label="Condition Upper Examples",
733
+ )
734
+ gr.Examples(
735
+ examples=[
736
+ os.path.join(root_path, "condition", "overall", _)
737
+ for _ in os.listdir(os.path.join(root_path, "condition", "overall"))
738
+ ],
739
+ examples_per_page=4,
740
+ inputs=cloth_image_flux,
741
+ label="Condition Overall Examples",
742
+ )
743
+ condition_person_exm = gr.Examples(
744
+ examples=[
745
+ os.path.join(root_path, "condition", "person", _)
746
+ for _ in os.listdir(os.path.join(root_path, "condition", "person"))
747
+ ],
748
+ examples_per_page=4,
749
+ inputs=cloth_image_flux,
750
+ label="Condition Reference Person Examples",
751
+ )
752
+ gr.Markdown(
753
+ '<span style="color: #808080; font-size: small;">*Condition examples come from the Internet. </span>'
754
+ )
755
+
756
+
757
+ image_path_flux.change(
758
+ person_example_fn, inputs=image_path_flux, outputs=person_image_flux
759
+ )
760
 
 
761
  submit_flux.click(
762
  submit_function_flux,
763
+ [person_image_flux, cloth_image_flux, cloth_type, num_inference_steps_flux, guidance_scale_flux, seed_flux, show_type],
 
 
 
 
 
 
 
 
764
  result_image_flux,
765
  )
766
+
767
+
768
+ with gr.Tab("Mask-free & SD1.5"):
769
  with gr.Row():
770
  with gr.Column(scale=1, min_width=350):
771
+ with gr.Row():
772
+ image_path_p2p = gr.Image(
773
+ type="filepath",
774
+ interactive=True,
775
+ visible=False,
776
+ )
777
+ person_image_p2p = gr.ImageEditor(
778
+ interactive=True, label="Person Image", type="filepath"
779
+ )
780
+
781
+ with gr.Row():
782
+ with gr.Column(scale=1, min_width=230):
783
+ cloth_image_p2p = gr.Image(
784
+ interactive=True, label="Condition Image", type="filepath"
785
+ )
786
+
787
  submit_p2p = gr.Button("Submit")
788
+ gr.Markdown(
789
+ '<center><span style="color: #FF0000">!!! Click only Once, Wait for Delay !!!</span></center>'
790
+ )
791
+
792
+ gr.Markdown(
793
+ '<span style="color: #808080; font-size: small;">Advanced options can adjust details:<br>1. `Inference Step` may enhance details;<br>2. `CFG` is highly correlated with saturation;<br>3. `Random seed` may improve pseudo-shadow.</span>'
794
+ )
795
  with gr.Accordion("Advanced Options", open=False):
796
+ num_inference_steps_p2p = gr.Slider(
797
+ label="Inference Step", minimum=10, maximum=100, step=5, value=50
798
+ )
799
+ # Guidence Scale
800
+ guidance_scale_p2p = gr.Slider(
801
+ label="CFG Strenth", minimum=0.0, maximum=7.5, step=0.5, value=2.5
802
+ )
803
+ # Random Seed
804
+ seed_p2p = gr.Slider(
805
+ label="Seed", minimum=-1, maximum=10000, step=1, value=42
806
+ )
807
+ # show_type = gr.Radio(
808
+ # label="Show Type",
809
+ # choices=["result only", "input & result", "input & mask & result"],
810
+ # value="input & mask & result",
811
+ # )
812
+
813
  with gr.Column(scale=2, min_width=500):
814
  result_image_p2p = gr.Image(interactive=False, label="Result")
815
+ with gr.Row():
816
+ # Photo Examples
817
+ root_path = "resource/demo/example"
818
+ with gr.Column():
819
+ gr.Examples(
820
+ examples=[
821
+ os.path.join(root_path, "person", "men", _)
822
+ for _ in os.listdir(os.path.join(root_path, "person", "men"))
823
+ ],
824
+ examples_per_page=4,
825
+ inputs=image_path_p2p,
826
+ label="Person Examples ①",
827
+ )
828
+ gr.Examples(
829
+ examples=[
830
+ os.path.join(root_path, "person", "women", _)
831
+ for _ in os.listdir(os.path.join(root_path, "person", "women"))
832
+ ],
833
+ examples_per_page=4,
834
+ inputs=image_path_p2p,
835
+ label="Person Examples ②",
836
+ )
837
+ gr.Markdown(
838
+ '<span style="color: #808080; font-size: small;">*Person examples come from the demos of <a href="https://huggingface.co/spaces/levihsu/OOTDiffusion">OOTDiffusion</a> and <a href="https://www.outfitanyone.org">OutfitAnyone</a>. </span>'
839
+ )
840
+ with gr.Column():
841
+ gr.Examples(
842
+ examples=[
843
+ os.path.join(root_path, "condition", "upper", _)
844
+ for _ in os.listdir(os.path.join(root_path, "condition", "upper"))
845
+ ],
846
+ examples_per_page=4,
847
+ inputs=cloth_image_p2p,
848
+ label="Condition Upper Examples",
849
+ )
850
+ gr.Examples(
851
+ examples=[
852
+ os.path.join(root_path, "condition", "overall", _)
853
+ for _ in os.listdir(os.path.join(root_path, "condition", "overall"))
854
+ ],
855
+ examples_per_page=4,
856
+ inputs=cloth_image_p2p,
857
+ label="Condition Overall Examples",
858
+ )
859
+ condition_person_exm = gr.Examples(
860
+ examples=[
861
+ os.path.join(root_path, "condition", "person", _)
862
+ for _ in os.listdir(os.path.join(root_path, "condition", "person"))
863
+ ],
864
+ examples_per_page=4,
865
+ inputs=cloth_image_p2p,
866
+ label="Condition Reference Person Examples",
867
+ )
868
+ gr.Markdown(
869
+ '<span style="color: #808080; font-size: small;">*Condition examples come from the Internet. </span>'
870
+ )
871
+
872
+ image_path_p2p.change(
873
+ person_example_fn, inputs=image_path_p2p, outputs=person_image_p2p
874
+ )
875
 
876
  submit_p2p.click(
877
  submit_function_p2p,
878
+ [
879
+ person_image_p2p,
880
+ cloth_image_p2p,
881
+ num_inference_steps_p2p,
882
+ guidance_scale_p2p,
883
+ seed_p2p],
884
  result_image_p2p,
885
  )
886
+
887
+ demo.queue().launch(share=True, show_error=True)
888
 
889
 
890
  if __name__ == "__main__":
891
+ app_gradio()