testone / app.py
Doradior's picture
Update app.py
b1ba448 verified
Raw History Blame Contribute Delete
3.98 kB
import os
import gradio as gr
import torch
import numpy as np
from PIL import Image
import cv2
from diffusers import StableDiffusionControlNetImg2ImgPipeline, ControlNetModel
import insightface
# ========== CONFIG ==========
device = "cpu"
dtype = torch.float32
BASE_MODEL = "runwayml/stable-diffusion-v1-5"
CONTROLNET_MODEL = "lllyasviel/control_v11e_sd15_reference_only"
# ========== UTILS ==========
def pil_to_cv(img):
return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
def cv_to_pil(img):
return Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
def make_grid(images, rows, cols):
w, h = images[0].size
grid = Image.new("RGB", (cols*w, rows*h))
for i, im in enumerate(images):
grid.paste(im, box=((i % cols) * w, (i // cols) * h))
return grid
# ========== LOAD MODELS ==========
print("πŸ”„ Loading ControlNet...")
controlnet = ControlNetModel.from_pretrained(CONTROLNET_MODEL, torch_dtype=dtype)
print("πŸ”„ Loading Stable Diffusion pipeline...")
pipe = StableDiffusionControlNetImg2ImgPipeline.from_pretrained(
BASE_MODEL,
controlnet=controlnet,
torch_dtype=dtype,
safety_checker=None
).to(device)
print("πŸ”„ Loading InsightFace (antelopev2)...")
ins_model = insightface.app.FaceAnalysis(name="antelopev2", providers=["CPUExecutionProvider"])
ins_model.prepare(ctx_id=0, det_size=(640, 640))
# ========== MAIN FUNCTION ==========
def generate_grid(init_image, prompt, neg_prompt, steps, cfg, strength, seed, width, height):
if init_image is None:
return None, "❌ Upload foto dulu."
# Deteksi wajah
cv_img = pil_to_cv(init_image)
faces = ins_model.get(cv_img)
if not faces:
return None, "❌ Wajah tidak terdeteksi."
# Ambil wajah terbesar
faces.sort(key=lambda f: (f.bbox[2]-f.bbox[0])*(f.bbox[3]-f.bbox[1]), reverse=True)
x1, y1, x2, y2 = map(int, faces[0].bbox)
face_crop = init_image.crop((x1, y1, x2, y2)).resize((width, height))
# Generator seed
g = torch.Generator(device=device)
if seed >= 0:
g.manual_seed(seed)
images = []
for i in range(9):
out = pipe(
prompt=prompt,
negative_prompt=neg_prompt if neg_prompt.strip() else None,
image=init_image.resize((width, height)),
control_image=face_crop,
num_inference_steps=steps,
guidance_scale=cfg,
strength=strength,
generator=torch.Generator(device=device).manual_seed(
seed if seed >= 0 else torch.seed()
)
).images[0]
images.append(out)
return make_grid(images, 3, 3), f"βœ… Face bbox: {x1},{y1},{x2},{y2}"
# ========== GRADIO UI ==========
with gr.Blocks() as demo:
gr.Markdown("## πŸ‘€ CPU Face Consistency 3Γ—3 Generator (ControlNet Reference-Only + InsightFace)")
with gr.Row():
with gr.Column():
init_image = gr.Image(label="Upload Foto Wajah", type="pil")
prompt = gr.Textbox(label="Prompt", value="studio portrait, soft lighting, ultra detailed skin")
neg_prompt = gr.Textbox(label="Negative Prompt", value="blurry, deformed, bad anatomy")
steps = gr.Slider(8, 25, 14, step=1, label="Steps")
cfg = gr.Slider(3, 12, 7.0, step=0.5, label="CFG Scale")
strength = gr.Slider(0.3, 0.8, 0.55, step=0.05, label="Denoising Strength")
width = gr.Slider(320, 512, 384, step=32, label="Width")
height = gr.Slider(320, 512, 384, step=32, label="Height")
seed = gr.Number(value=-1, precision=0, label="Seed (-1 = acak)")
run = gr.Button("Generate 3Γ—3")
with gr.Column():
out_img = gr.Image(label="Output Grid")
log = gr.Markdown()
run.click(
fn=generate_grid,
inputs=[init_image, prompt, neg_prompt, steps, cfg, strength, seed, width, height],
outputs=[out_img, log]
)
if __name__ == "__main__":
demo.launch()