Update app.py
Browse files
app.py
CHANGED
|
@@ -222,6 +222,26 @@ SPACES: Dict[str, Dict[str, Any]] = {
|
|
| 222 |
# ---------------------------------
|
| 223 |
# Utility
|
| 224 |
# ---------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
def _save_png(img: Image.Image, path: Union[str,Path]) -> str:
|
| 226 |
p = Path(path); p.parent.mkdir(parents=True, exist_ok=True); img.save(p); return str(p)
|
| 227 |
|
|
@@ -635,50 +655,47 @@ def step1_gpu_refine(
|
|
| 635 |
|
| 636 |
# ---- T-포즈 (ControlNet/OpenPose)
|
| 637 |
if enforce_tpose:
|
| 638 |
-
|
| 639 |
-
|
| 640 |
-
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
| 655 |
-
|
| 656 |
-
|
| 657 |
-
|
| 658 |
-
|
| 659 |
-
|
| 660 |
-
|
| 661 |
-
|
| 662 |
-
|
| 663 |
-
|
| 664 |
-
|
| 665 |
-
|
| 666 |
-
|
| 667 |
-
|
| 668 |
-
|
| 669 |
-
|
| 670 |
-
|
| 671 |
-
|
| 672 |
-
|
| 673 |
-
|
| 674 |
-
|
| 675 |
-
).
|
| 676 |
-
|
| 677 |
-
img = out.convert("RGBA")
|
| 678 |
img.save(OUT/"step1"/"dbg_03_after_tpose.png")
|
| 679 |
-
logs.append("ControlNet(OpenPose) T-포즈 적용
|
| 680 |
-
|
| 681 |
-
logs.append(f"T-포즈 ControlNet 실패: {e}")
|
| 682 |
|
| 683 |
# ---- (옵션) 리드로우(img2img)
|
| 684 |
if do_redraw_flag:
|
|
|
|
| 222 |
# ---------------------------------
|
| 223 |
# Utility
|
| 224 |
# ---------------------------------
|
| 225 |
+
def _openpose_canvas_from_image(img_rgb: Image.Image) -> Image.Image:
|
| 226 |
+
try:
|
| 227 |
+
if PKG.get("OpenposeDetector") is None:
|
| 228 |
+
return Image.new("RGB", img_rgb.size, "black")
|
| 229 |
+
det = PKG["OpenposeDetector"]()
|
| 230 |
+
pose = det(img_rgb)
|
| 231 |
+
return pose.convert("RGB").resize(img_rgb.size)
|
| 232 |
+
except Exception:
|
| 233 |
+
return Image.new("RGB", img_rgb.size, "black")
|
| 234 |
+
|
| 235 |
+
def _blend_pose_canvases(orig_pose: Image.Image, tpose: Image.Image, alpha: float = 0.4) -> Image.Image:
|
| 236 |
+
alpha = max(0.0, min(1.0, float(alpha)))
|
| 237 |
+
if orig_pose.size != tpose.size:
|
| 238 |
+
tpose = tpose.resize(orig_pose.size)
|
| 239 |
+
return Image.blend(orig_pose, tpose, alpha).convert("RGB")
|
| 240 |
+
|
| 241 |
+
def _mean_brightness(img: Image.Image) -> float:
|
| 242 |
+
import numpy as np
|
| 243 |
+
return float(np.asarray(img.convert("L"), dtype=np.uint8).mean())
|
| 244 |
+
|
| 245 |
def _save_png(img: Image.Image, path: Union[str,Path]) -> str:
|
| 246 |
p = Path(path); p.parent.mkdir(parents=True, exist_ok=True); img.save(p); return str(p)
|
| 247 |
|
|
|
|
| 655 |
|
| 656 |
# ---- T-포즈 (ControlNet/OpenPose)
|
| 657 |
if enforce_tpose:
|
| 658 |
+
from diffusers import ControlNetModel, StableDiffusionControlNetImg2ImgPipeline, EulerAncestralDiscreteScheduler
|
| 659 |
+
import torch
|
| 660 |
+
dev = "cuda" if torch.cuda.is_available() else "cpu"
|
| 661 |
+
dtype = torch.float16 if dev == "cuda" else torch.float32
|
| 662 |
+
|
| 663 |
+
controlnet = ControlNetModel.from_pretrained("lllyasviel/control_v11p_sd15_openpose", torch_dtype=dtype)
|
| 664 |
+
pipe_pose = StableDiffusionControlNetImg2ImgPipeline.from_pretrained(
|
| 665 |
+
"runwayml/stable-diffusion-v1-5", controlnet=controlnet, torch_dtype=dtype
|
| 666 |
+
)
|
| 667 |
+
try: pipe_pose.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe_pose.scheduler.config)
|
| 668 |
+
except: pass
|
| 669 |
+
if dev == "cuda": pipe_pose.to("cuda")
|
| 670 |
+
|
| 671 |
+
img_rgb = _resize_to_multiple(img.convert("RGB"), multiple=8, max_side=512)
|
| 672 |
+
pose_orig = _openpose_canvas_from_image(img_rgb)
|
| 673 |
+
pose_tpose = _draw_tpose_openpose_canvas(size=min(img_rgb.size)) # 기존 T-포즈 가이드
|
| 674 |
+
pose_canvas= _blend_pose_canvases(pose_orig, pose_tpose, alpha=0.4)
|
| 675 |
+
|
| 676 |
+
out = pipe_pose(
|
| 677 |
+
prompt="T-pose tendency, full body, same outfit and colors, clean anime lines, plain light background",
|
| 678 |
+
negative_prompt="extra limbs, deformed, melted face, distorted body, watermark, text, noisy",
|
| 679 |
+
image=img_rgb,
|
| 680 |
+
control_image=pose_canvas,
|
| 681 |
+
strength=float(tpose_strength), # (클램프됨)
|
| 682 |
+
guidance_scale=float(tpose_guidance),
|
| 683 |
+
num_inference_steps=int(tpose_steps),
|
| 684 |
+
controlnet_conditioning_scale=0.30, # ★ 낮춤
|
| 685 |
+
control_guidance_start=[0.0],
|
| 686 |
+
control_guidance_end=[0.50], # ★ 중반까지만
|
| 687 |
+
guess_mode=True # ★ 배경/미세영역 과제어 방지
|
| 688 |
+
).images[0]
|
| 689 |
+
|
| 690 |
+
img = out.convert("RGBA")
|
| 691 |
+
if _mean_brightness(img) < 12:
|
| 692 |
+
logs.append("T-포즈 결과가 너무 어두움 → 원본으로 롤백")
|
| 693 |
+
img = Image.open(s1_path).convert("RGBA")
|
| 694 |
+
else:
|
| 695 |
+
(OUT/"step1"/"dbg_pose_orig.png").write_bytes(pose_orig.tobytes()) if False else None
|
|
|
|
|
|
|
| 696 |
img.save(OUT/"step1"/"dbg_03_after_tpose.png")
|
| 697 |
+
logs.append("ControlNet(OpenPose) T-포즈(블렌드) 적용")
|
| 698 |
+
|
|
|
|
| 699 |
|
| 700 |
# ---- (옵션) 리드로우(img2img)
|
| 701 |
if do_redraw_flag:
|