aptol commited on
Commit
3153d6a
ยท
verified ยท
1 Parent(s): 70e511b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +102 -85
app.py CHANGED
@@ -689,68 +689,117 @@ def step1_gpu_refine(
689
  except Exception:
690
  dev = "cpu"; dtype = None # type: ignore
691
 
692
- # ---- T-ํฌ์ฆˆ (ControlNet/OpenPose)
693
  if enforce_tpose:
694
  try:
 
 
695
  from diffusers import (
696
  ControlNetModel,
697
  StableDiffusionControlNetImg2ImgPipeline,
698
  DPMSolverMultistepScheduler
699
  )
700
- import torch, math
 
701
 
702
  dev = "cuda" if torch.cuda.is_available() else "cpu"
703
  dtype = torch.float16 if dev == "cuda" else torch.float32
704
 
705
- # 1) ControlNet ๋กœ๋“œ
706
- controlnet = ControlNetModel.from_pretrained(
707
- "lllyasviel/control_v11p_sd15_openpose",
708
- torch_dtype=dtype
 
 
 
 
 
 
 
709
  )
710
- pipe_pose = StableDiffusionControlNetImg2ImgPipeline.from_pretrained(
 
 
 
 
 
 
711
  "runwayml/stable-diffusion-v1-5",
712
  controlnet=controlnet,
713
  torch_dtype=dtype,
714
- safety_checker=None,
715
- feature_extractor=None,
716
  )
717
- # ์„ธ์ดํ”„ํ‹ฐ ์™„์ „ ๋น„ํ™œ์„ฑ (์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ์œ ํ‹ธ)
718
- pipe_pose = _disable_safety(pipe_pose)
719
-
720
- # โ˜… ๋” ์•ˆ์ •์ ์ธ Karras DPM-Solver
721
  try:
722
- pipe_pose.scheduler = DPMSolverMultistepScheduler.from_config(
723
- pipe_pose.scheduler.config,
724
- use_karras_sigmas=True
725
  )
726
  except Exception:
727
  pass
728
-
729
- if dev == "cuda": pipe_pose.to("cuda")
730
  try:
731
- pipe_pose.enable_vae_slicing()
732
  except Exception:
733
  pass
734
 
735
- # 2) ์ž…๋ ฅ/ํฌ์ฆˆ ์ค€๋น„ (ํ•ด์ƒ๋„ ํ†ต์ผ + 8๋ฐฐ์ˆ˜)
736
- base_rgb = _resize_to_multiple(img.convert("RGB"), multiple=8, max_side=512)
 
 
 
737
 
738
- # ์›๋ณธ ํฌ์ฆˆ๋ฅผ ์ถ”์ถœํ•ด์„œ Tํฌ์ฆˆ์™€ '์•ฝํ•˜๊ฒŒ' ๋ธ”๋ Œ๋“œ(0.2)
739
- pose_orig = _openpose_canvas_from_image(base_rgb) # ์›๋ณธ ํฌ์ฆˆ(์Šค์ผˆ๋ ˆํ†ค)
740
- pose_t = _make_tpose_canvas_like(base_rgb) # ์šฐ๋ฆฌ๊ฐ€ ๊ทธ๋ฆฐ Tํฌ์ฆˆ ์บ”๋ฒ„์Šค
741
- pose_canvas= _blend_pose_canvases(pose_orig, pose_t, alpha=0.20).resize(base_rgb.size)
 
 
 
 
 
742
 
743
- # ์„ ์ด ๋„ˆ๋ฌด ์–‡์œผ๋ฉด ์ˆ˜๋ ด์ด ํ”๋“ค๋ ค์„œ ๋‘๊ป๊ฒŒ ๊ฐ•ํ™”
744
- try:
745
- from PIL import ImageDraw
746
- pc = pose_canvas.copy()
747
- draw = ImageDraw.Draw(pc)
748
- # ํ…Œ๋‘๋ฆฌ ๊ฐ•ํ™”(ํ•˜์–€ ํ”„๋ ˆ์ž„์„ ๋”ํ•จ)
749
- w,h = pc.size
750
- draw.rectangle([2,2,w-3,h-3], outline=(255,255,255), width=2)
751
- pose_canvas = pc
752
- except Exception:
753
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
754
 
755
  # 3) ํ”„๋กœใƒณใƒ—ํŠธ (๋ฐ๊ณ  ๋‹จ์ˆœํ•œ ๋ฐฐ๊ฒฝ + NSFW ๋ฐฉ์ง€ ๋‹จ์–ด)
756
  POS = (
@@ -798,31 +847,7 @@ def step1_gpu_refine(
798
 
799
  out = out_b
800
 
801
- # 5) ์–ผ๊ตด ๋ณดํ˜ธ(์›๋ณธ์—์„œ ์–ผ๊ตด๋งŒ ๋ณต์›): ๊ฐ„๋‹จํ•œ ๋ฐ๊ธฐ/์ƒ‰ ๊ธฐ๋ฐ˜ ๋ฐ•์Šค ์ถ”์ •
802
- try:
803
- # ์–ผ๊ตด ๋ฐ•์Šค๋ฅผ MediaPipe ์—†์ด ์ถ”์ •(๋Œ€์ถฉ ์ƒ๋‹จ ์ค‘์•™ 30~35%)
804
- W,H = out.size
805
- cx, cy = W//2, int(H*0.30)
806
- bw, bh = int(W*0.36), int(H*0.28)
807
- x1, y1 = max(0, cx-bw//2), max(0, cy-bh//2)
808
- x2, y2 = min(W, cx+bw//2), min(H, cy+bh//2)
809
-
810
- face_new = out.crop((x1,y1,x2,y2))
811
- face_old = Image.open(s1_path).convert("RGBA").resize((W,H), Image.LANCZOS).crop((x1,y1,x2,y2))
812
-
813
- # ์†Œํ”„ํŠธ ๋งˆ์Šคํฌ๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฎ์–ด์”Œ์šฐ๊ธฐ
814
- import numpy as np
815
- m = Image.new("L", (x2-x1, y2-y1), 0)
816
- from PIL import ImageFilter
817
- # ํƒ€์›ํ˜• ๋งˆ์Šคํฌ
818
- mm = Image.new("L", m.size, 0)
819
- draw = ImageDraw.Draw(mm)
820
- draw.ellipse([4,4,mm.size[0]-5,mm.size[1]-5], fill=255)
821
- mm = mm.filter(ImageFilter.GaussianBlur(6))
822
- face_mix = Image.composite(face_old, face_new, mm)
823
- out.paste(face_mix, (x1,y1), mm)
824
- except Exception:
825
- pass
826
 
827
  # 6) ๋„ˆ๋ฌด ์–ด๋‘์šฐ๋ฉด ๋ฐ๊ธฐ ๋ฆฌํ”„ํŠธ + ์‹คํŒจ ์‹œ ์›๋ณธ ๋กค๋ฐฑ
828
  if _mean_brightness(out) < 16:
@@ -840,34 +865,26 @@ def step1_gpu_refine(
840
 
841
 
842
 
843
- # ---- (์˜ต์…˜) ๋ฆฌ๋“œ๋กœ์šฐ(img2img)
844
- if do_redraw_flag:
845
- try:
846
  from diffusers import StableDiffusionImg2ImgPipeline
847
- pipe_redraw = StableDiffusionImg2ImgPipeline.from_pretrained(
848
- "runwayml/stable-diffusion-v1-5",
849
- torch_dtype=dtype,
850
- safety_checker=None,
851
- feature_extractor=None,
852
  )
853
- pipe_redraw = _disable_safety(pipe_redraw)
 
 
 
 
 
 
 
 
 
 
854
 
855
 
856
- if dev == "cuda":
857
- pipe_redraw.to("cuda")
858
-
859
- img_for_redraw = _resize_to_multiple(img.convert("RGB"), multiple=8, max_side=768)
860
- Image.fromarray(img_for_redraw).save(OUT/"step1"/"dbg_04_before_redraw.png")
861
-
862
- out = pipe_redraw(
863
- prompt="clean anime illustration, sharp lines, simple solid background, same outfit and colors",
864
- negative_prompt="deformed, extra limbs, bad anatomy, watermark, text, noisy",
865
- image=img_for_redraw,
866
- strength=float(redraw_strength),
867
- guidance_scale=float(redraw_guidance),
868
- num_inference_steps=int(redraw_steps),
869
- ).images[0]
870
-
871
  img = out.convert("RGBA")
872
  img.save(OUT/"step1"/"dbg_05_after_redraw.png")
873
  logs.append("img2img ๋ฆฌ๋“œ๋กœ์šฐ ์ ์šฉ")
 
689
  except Exception:
690
  dev = "cpu"; dtype = None # type: ignore
691
 
 
692
  if enforce_tpose:
693
  try:
694
+ import math, torch
695
+ from PIL import Image
696
  from diffusers import (
697
  ControlNetModel,
698
  StableDiffusionControlNetImg2ImgPipeline,
699
  DPMSolverMultistepScheduler
700
  )
701
+ from diffusers.utils import load_image
702
+ from diffusers.pipelines.controlnet.multicontrolnet import MultiControlNetModel
703
 
704
  dev = "cuda" if torch.cuda.is_available() else "cpu"
705
  dtype = torch.float16 if dev == "cuda" else torch.float32
706
 
707
+ # --- ์ž…๋ ฅ/์บ”๋ฒ„์Šค ์ค€๋น„ ---
708
+ base_rgb = _resize_to_multiple(img.convert("RGB"), multiple=8, max_side=512)
709
+
710
+ # ์›๋ณธ ํฌ์ฆˆ ์บ”๋ฒ„์Šค + Tํฌ์ฆˆ ์บ”๋ฒ„์Šค โ†’ ์•ฝ๋ธ”๋ Œ๋“œ(์›๋ณธ 80% : T 20%)
711
+ pose_orig = _openpose_canvas_from_image(base_rgb)
712
+ pose_t = _make_tpose_canvas_like(base_rgb)
713
+ pose_canvas= _blend_pose_canvases(pose_orig, pose_t, alpha=0.20).resize(base_rgb.size)
714
+
715
+ # --- Dual ControlNet: OpenPose + Reference-Only ---
716
+ cn_pose = ControlNetModel.from_pretrained(
717
+ "lllyasviel/control_v11p_sd15_openpose", torch_dtype=dtype
718
  )
719
+ cn_ref = ControlNetModel.from_pretrained(
720
+ "lllyasviel/control_v11f1e_sd15_tile", torch_dtype=dtype
721
+ )
722
+ # ์ฐธ๊ณ : reference-only๋Š” tile ๋ชจ๋ธ์—์„œ ref ๋ชจ๋“œ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
723
+ controlnet = MultiControlNetModel([cn_pose, cn_ref])
724
+
725
+ pipe = StableDiffusionControlNetImg2ImgPipeline.from_pretrained(
726
  "runwayml/stable-diffusion-v1-5",
727
  controlnet=controlnet,
728
  torch_dtype=dtype,
729
+ safety_checker=None, feature_extractor=None,
 
730
  )
731
+ pipe = _disable_safety(pipe)
 
 
 
732
  try:
733
+ pipe.scheduler = DPMSolverMultistepScheduler.from_config(
734
+ pipe.scheduler.config, use_karras_sigmas=True
 
735
  )
736
  except Exception:
737
  pass
738
+ if dev == "cuda":
739
+ pipe.to("cuda")
740
  try:
741
+ pipe.enable_vae_slicing()
742
  except Exception:
743
  pass
744
 
745
+ # --- ์ปจ๋””์…˜ ์ด๋ฏธ์ง€ 2๊ฐœ ์ค€๋น„ ---
746
+ control_images = [
747
+ pose_canvas, # 0: ํฌ์ฆˆ
748
+ base_rgb # 1: ๋ ˆํผ๋Ÿฐ์Šค(์ƒ‰/ํ…์Šค์ฒ˜)
749
+ ]
750
 
751
+ # --- ํ”„๋กฌํ”„ํŠธ ---
752
+ POS = (
753
+ "clean anime illustration, full body, sharp lines, same outfit and colors as reference, "
754
+ "T-pose tendency, white studio background, bright, high-key lighting"
755
+ )
756
+ NEG = (
757
+ "glitch, collage, cutout, fragments, abstract shapes, mosaic, compression artifacts, "
758
+ "extra limbs, extra fingers, deformed, melted, noisy, text, watermark, black background"
759
+ )
760
 
761
+ # --- ํŒŒ๋ผ๋ฏธ๏ฟฝ๏ฟฝ (์•ˆ์ •๊ฐ’) ---
762
+ steps = int(max(16, min(28, int(tpose_steps))))
763
+ strength = float(max(0.50, min(0.65, float(tpose_strength))))
764
+ guidance = float(max(7.0, min(9.5, float(tpose_guidance))))
765
+ # controlnet ์˜ํ–ฅ: [OpenPose, Reference]
766
+ cond_scales = [0.22, 0.70] # ํฌ์ฆˆ๋Š” ์•ฝํ•˜๊ฒŒ, ๋ ˆํผ๋Ÿฐ์Šค๋Š” ๊ฐ•ํ•˜๊ฒŒ
767
+ start_list = [0.05, 0.00] # ํฌ์ฆˆ๋Š” ์ดˆ๋ฐ˜๋ถ€ํ„ฐ, ๋ ˆํผ๋Ÿฐ์Šค๋Š” ์ „ ๊ตฌ๊ฐ„
768
+ end_list = [0.35, 0.80] # ํฌ์ฆˆ๋Š” ์ค‘๋ฐ˜๊นŒ์ง€๋งŒ, ๋ ˆํผ๋Ÿฐ์Šค๋Š” ์˜ค๋ž˜
769
+
770
+ # --- ์‹คํ–‰ ---
771
+ out = pipe(
772
+ prompt=POS, negative_prompt=NEG,
773
+ image=base_rgb,
774
+ control_image=control_images,
775
+ num_inference_steps=steps,
776
+ strength=strength,
777
+ guidance_scale=guidance,
778
+ controlnet_conditioning_scale=cond_scales,
779
+ control_guidance_start=start_list,
780
+ control_guidance_end=end_list,
781
+ guess_mode=True,
782
+ # reference-only ๋ชจ๋“œ: tile controlnet์— ์ ์šฉ๋˜๋Š” ํžŒํŠธ ํ† ๊ธ€
783
+ # (diffusers 0.29 ๊ธฐ์ค€, tile์€ ref-like ์—ญํ• ๋กœ ์ถฉ๋ถ„)
784
+ ).images[0].convert("RGBA")
785
+
786
+ # --- ์–ด๋‘์›€ ๊ฐ€๋“œ + ๋ฐ๊ธฐ ๋ฆฌํ”„ํŠธ ---
787
+ if _mean_brightness(out) < 16:
788
+ out = _lift_brightness(out, gain=1.18, gamma=0.90)
789
+ if _mean_brightness(out) < 12:
790
+ logs.append("T-ํฌ์ฆˆ(DualCN) ๊ฒฐ๊ณผ๊ฐ€ ์–ด๋‘์›Œ ์›๋ณธ ์œ ์ง€")
791
+ else:
792
+ img = out
793
+ try:
794
+ pose_canvas.save(OUT/"step1"/"dbg_pose_blend.png")
795
+ img.save(OUT/"step1"/"dbg_03_after_dualcn.png")
796
+ except Exception:
797
+ pass
798
+ logs.append("T-ํฌ์ฆˆ(Dual-ControlNet) ์ ์šฉ: Pose 0.22 + Reference 0.70")
799
+
800
+ except Exception as e:
801
+ logs.append(f"T-ํฌ์ฆˆ Dual-ControlNet ์‹คํŒจ: {e}")
802
+
803
 
804
  # 3) ํ”„๋กœใƒณใƒ—ํŠธ (๋ฐ๊ณ  ๋‹จ์ˆœํ•œ ๋ฐฐ๊ฒฝ + NSFW ๋ฐฉ์ง€ ๋‹จ์–ด)
805
  POS = (
 
847
 
848
  out = out_b
849
 
850
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
851
 
852
  # 6) ๋„ˆ๋ฌด ์–ด๋‘์šฐ๋ฉด ๋ฐ๊ธฐ ๋ฆฌํ”„ํŠธ + ์‹คํŒจ ์‹œ ์›๋ณธ ๋กค๋ฐฑ
853
  if _mean_brightness(out) < 16:
 
865
 
866
 
867
 
868
+ # ---- (์˜ต์…˜) ๋ฆฌ๋“œ๋กœ์šฐ(img2img)
869
+ if do_redraw_flag:
 
870
  from diffusers import StableDiffusionImg2ImgPipeline
871
+ pr = StableDiffusionImg2ImgPipeline.from_pretrained(
872
+ "runwayml/stable-diffusion-v1-5", torch_dtype=dtype,
873
+ safety_checker=None, feature_extractor=None
 
 
874
  )
875
+ pr = _disable_safety(pr)
876
+ if dev == "cuda": pr.to("cuda")
877
+ img_for = _resize_to_multiple(img.convert("RGB"), 8, 640)
878
+ img = pr(
879
+ prompt="clean anime illustration, sharp lines, flat colors, plain white background",
880
+ negative_prompt="glitch, mosaic, text, watermark, noisy",
881
+ image=img_for,
882
+ strength=float(max(0.30, min(0.45, float(redraw_strength)))),
883
+ guidance_scale=float(max(6.5, min(9.0, float(redraw_guidance)))),
884
+ num_inference_steps=int(max(14, min(28, int(redraw_steps)))),
885
+ ).images[0].convert("RGBA")
886
 
887
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
888
  img = out.convert("RGBA")
889
  img.save(OUT/"step1"/"dbg_05_after_redraw.png")
890
  logs.append("img2img ๋ฆฌ๋“œ๋กœ์šฐ ์ ์šฉ")