model-change / app.py
Peace-Network's picture
Create app.py
ecb3e52 verified
Raw
History Blame Contribute Delete
4.17 kB
import spaces
import gradio as gr
import torch
from PIL import Image
from torchvision import transforms
from transformers import AutoModelForImageSegmentation
torch.set_float32_matmul_precision("high")
print("Loading BiRefNet...")
birefnet = AutoModelForImageSegmentation.from_pretrained(
"ZhengPeng7/BiRefNet", trust_remote_code=True
)
birefnet.to("cuda")
birefnet.eval()
birefnet.half()
print("Model ready.")
IMAGE_SIZE = (1024, 1024)
transform_image = transforms.Compose([
transforms.Resize(IMAGE_SIZE),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
])
@spaces.GPU(duration=30)
def cutout_model(image: Image.Image):
"""Removes the background from the model photo, returns RGBA cutout."""
original = image.convert("RGB")
input_tensor = transform_image(original).unsqueeze(0).to("cuda").half()
with torch.no_grad():
preds = birefnet(input_tensor)[-1].sigmoid().cpu()
mask = preds[0].squeeze()
mask_pil = transforms.ToPILImage()(mask).resize(original.size)
cutout = original.copy()
cutout.putalpha(mask_pil)
return cutout
def compose_thumbnail(thumbnail, model_photo, scale, x_pos, y_pos):
if thumbnail is None:
raise gr.Error("Please upload a thumbnail/background image.")
if model_photo is None:
raise gr.Error("Please upload a model photo.")
try:
thumbnail = thumbnail.convert("RGBA")
cutout = cutout_model(model_photo)
# Scale the cutout relative to the thumbnail's height
thumb_w, thumb_h = thumbnail.size
target_h = int(thumb_h * (scale / 100.0))
aspect = cutout.width / cutout.height
target_w = int(target_h * aspect)
cutout_resized = cutout.resize((target_w, target_h), Image.LANCZOS)
# Position: x_pos/y_pos are percentages of thumbnail width/height,
# representing where the CENTER of the cutout should land.
center_x = int(thumb_w * (x_pos / 100.0))
center_y = int(thumb_h * (y_pos / 100.0))
paste_x = center_x - target_w // 2
paste_y = center_y - target_h // 2
result = thumbnail.copy()
result.paste(cutout_resized, (paste_x, paste_y), cutout_resized)
return result.convert("RGB")
except Exception as e:
import traceback
traceback.print_exc()
raise gr.Error(f"Compositing failed: {e}")
css = """
#header {
text-align: center;
padding: 24px 0 8px;
}
#header h1 {
font-size: 32px;
font-weight: 700;
background: linear-gradient(135deg, #6366f1, #06b6d4);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 4px;
}
#header p {
color: #888;
font-size: 14px;
}
#run-btn {
background: linear-gradient(135deg, #6366f1, #06b6d4) !important;
color: white !important;
font-weight: 600 !important;
border: none !important;
}
"""
with gr.Blocks(title="Peace Network Thumbnail Composer", css=css) as demo:
gr.HTML(
"""
<div id="header">
<h1>🎬 Peace Network Thumbnail Composer</h1>
<p>Thumbnail background + model photo daaliye — model automatically fit ho jayega.</p>
</div>
"""
)
with gr.Row():
thumb_input = gr.Image(type="pil", label="1. Thumbnail / background")
model_input = gr.Image(type="pil", label="2. Model photo")
with gr.Row():
scale_slider = gr.Slider(
minimum=10, maximum=100, value=60, step=1,
label="Model size (% of thumbnail height)"
)
x_slider = gr.Slider(
minimum=0, maximum=100, value=50, step=1,
label="Horizontal position (%)"
)
y_slider = gr.Slider(
minimum=0, maximum=100, value=70, step=1,
label="Vertical position (%)"
)
btn = gr.Button("✨ Compose Thumbnail", variant="primary", elem_id="run-btn")
output = gr.Image(type="pil", label="Result")
btn.click(
compose_thumbnail,
inputs=[thumb_input, model_input, scale_slider, x_slider, y_slider],
outputs=output,
)
demo.queue().launch()