Tryonn / app.py
Zuii's picture
Update app.py
4f1e299 verified
raw
history blame
8.55 kB
import os
import requests
import json
import time
import cv2
import base64
import random
import numpy as np
import gradio as gr
MAX_SEED = 999999
# βœ… Pixelcut API Key
pixelcut_api_key = "sk_299d9c6e36d240cbb3dd65fcbac947a4"
# βœ… ImgBB API Key (for uploading images to get valid URLs)
imgbb_api_key = "03a2ddf1ffa5df33a3999cf20c2fb20f"
# 🎯 Convert image to PNG format
def convert_to_png(image):
return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# πŸ”₯ Resize large images to prevent upload failures (ImgBB limit: 32MB)
def resize_image(image, max_size=1024):
height, width = image.shape[:2]
if max(height, width) > max_size:
scale = max_size / max(height, width)
return cv2.resize(image, (int(width * scale), int(height * scale)))
return image
# πŸ› οΈ Upload images to ImgBB (fixed payload!)
def upload_image_to_imgbb(image_data):
url = f"https://api.imgbb.com/1/upload?key={imgbb_api_key}"
files = {"image": image_data}
response = requests.post(url, files=files)
if response.status_code == 200:
return response.json().get("data", {}).get("url")
else:
print("❌ ImgBB upload failed:", response.text)
return None
# πŸš€ Main try-on function using Pixelcut API
def tryon(person_img, garment_img, seed, randomize_seed):
start_time = time.time()
# πŸ›‘ Check if images are provided
if person_img is None or garment_img is None:
return None, None, "Empty image"
# 🎲 Handle seed randomization
if randomize_seed:
seed = random.randint(0, MAX_SEED)
# πŸ”₯ Convert and resize images to base64 PNG
person_img = resize_image(convert_to_png(person_img))
garment_img = resize_image(convert_to_png(garment_img))
_, person_encoded = cv2.imencode('.png', person_img)
_, garment_encoded = cv2.imencode('.png', garment_img)
# βœ… Upload person and garment images to get valid URLs
print("πŸ“€ Uploading person image...")
person_url = upload_image_to_imgbb(person_encoded)
print("πŸ“€ Uploading garment image...")
garment_url = upload_image_to_imgbb(garment_encoded)
if not person_url or not garment_url:
return None, None, "Image upload failed β€” check API keys or connection"
# 🌟 Setup Pixelcut API endpoint and headers
url = "https://api.developer.pixelcut.ai/v1/remove-background"
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-API-KEY': pixelcut_api_key
}
# πŸ”§ Use the uploaded URLs in the payload
person_data = {"image_url": person_url, "format": "png"}
garment_data = {"image_url": garment_url, "format": "png"}
result_img = None
max_retries = 5
retry_delay = 3 # Faster retries now!
try:
session = requests.Session()
# πŸ› οΈ Ensure both images are resized to 256x256
person_img = cv2.resize(person_img, (256, 256))
garment_img = cv2.resize(garment_img, (256, 256))
# 🎯 Handle transparency if the garment has an alpha channel
if garment_img.shape[-1] == 4:
alpha = garment_img[:, :, 3] / 255.0
for c in range(0, 3):
person_img[:, :, c] = (1 - alpha) * person_img[:, :, c] + alpha * garment_img[:, :, c]
# πŸ”§ Optional: Center the garment on the torso area
h, w, _ = person_img.shape
g_h, g_w, _ = garment_img.shape
x_offset = (w - g_w) // 2
y_offset = int(h * 0.35) # Adjust this value for higher/lower garment placement
person_img[y_offset:y_offset + g_h, x_offset:x_offset + g_w] = garment_img
# βœ… Now the rest of your code continues here (retry loop, API call, etc.)
except requests.exceptions.ReadTimeout:
print("Timeout!")
info = "⚑ Timeout β€” please try again later"
raise gr.Error("Too many users, please try again later")
except Exception as err:
print(f"❌ Other error: {err}")
info = "Error, please contact the admin"
example_path = os.path.join(os.path.dirname(__file__), 'assets')
garm_list = os.listdir(os.path.join(example_path,"cloth"))
garm_list_path = [os.path.join(example_path,"cloth",garm) for garm in garm_list]
human_list = os.listdir(os.path.join(example_path,"human"))
human_list_path = [os.path.join(example_path,"human",human) for human in human_list]
css="""
#col-left {
margin: 0 auto;
max-width: 430px;
}
#col-mid {
margin: 0 auto;
max-width: 430px;
}
#col-right {
margin: 0 auto;
max-width: 430px;
}
#col-showcase {
margin: 0 auto;
max-width: 1100px;
}
#button {
color: blue;
}
"""
def load_description(fp):
with open(fp, 'r', encoding='utf-8') as f:
content = f.read()
return content
def change_imgs(image1, image2):
return image1, image2
with gr.Blocks(css=css) as Tryon:
gr.HTML(load_description("assets/new_title.md"))
with gr.Row():
with gr.Column(elem_id = "col-left"):
gr.HTML("""
<div style="display: flex; justify-content: center; align-items: center; text-align: center; font-size: 20px;">
<div>
Step 1. Upload a person image ⬇️
</div>
</div>
""")
with gr.Column(elem_id = "col-mid"):
gr.HTML("""
<div style="display: flex; justify-content: center; align-items: center; text-align: center; font-size: 20px;">
<div>
Step 2. Upload a garment image ⬇️
</div>
</div>
""")
with gr.Column(elem_id = "col-right"):
gr.HTML("""
<div style="display: flex; justify-content: center; align-items: center; text-align: center; font-size: 20px;">
<div>
Step 3. Press β€œRun” to get try-on results
</div>
</div>
""")
with gr.Row():
with gr.Column(elem_id = "col-left"):
imgs = gr.Image(label="Person image", sources='upload', type="numpy")
# category = gr.Dropdown(label="Garment category", choices=['upper_body', 'lower_body', 'dresses'], value="upper_body")
example = gr.Examples(
inputs=imgs,
examples_per_page=12,
examples=human_list_path
)
with gr.Column(elem_id = "col-mid"):
garm_img = gr.Image(label="Garment image", sources='upload', type="numpy")
example = gr.Examples(
inputs=garm_img,
examples_per_page=12,
examples=garm_list_path
)
with gr.Column(elem_id = "col-right"):
image_out = gr.Image(label="Result", show_share_button=False)
with gr.Row():
seed = gr.Slider(
label="Seed",
minimum=0,
maximum=MAX_SEED,
step=1,
value=0,
)
randomize_seed = gr.Checkbox(label="Random seed", value=True)
with gr.Row():
seed_used = gr.Number(label="Seed used")
result_info = gr.Text(label="Response")
# try_button = gr.Button(value="Run", elem_id="button")
test_button = gr.Button(value="Run", elem_id="button")
# try_button.click(fn=start_tryon, inputs=[imgs, garm_img, seed, randomize_seed], outputs=[image_out, seed_used, result_info], api_name='tryon',concurrency_limit=10)
test_button.click(fn=tryon, inputs=[imgs, garm_img, seed, randomize_seed], outputs=[image_out, seed_used, result_info], api_name=False, concurrency_limit=45)
with gr.Column(elem_id = "col-showcase"):
gr.HTML("""
<div style="display: flex; justify-content: center; align-items: center; text-align: center; font-size: 20px;">
<div> </div>
<br>
<div>
Virtual try-on examples in pairs of person and garment images
</div>
</div>
""")
show_case = gr.Examples(
examples=[
["assets/examples/model2.png", "assets/examples/garment2.png", "assets/examples/result2.png"],
["assets/examples/model3.png", "assets/examples/garment3.png", "assets/examples/result3.png"],
["assets/examples/model1.png", "assets/examples/garment1.png", "assets/examples/result1.png"],
],
inputs=[imgs, garm_img, image_out],
label=None
)
Tryon.queue(api_open=False).launch(show_api=False)