Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
| import os | |
| import cv2 | |
| import gradio as gr | |
| import numpy as np | |
| import random | |
| import base64 | |
| import requests | |
| import json | |
| import time | |
| from PIL import Image | |
| def tryon(person_img, garment_img, seed, randomize_seed): | |
| post_start_time = time.time() | |
| if person_img is None or garment_img is None: | |
| gr.Warning("Empty image") | |
| return None, None, "Empty image" | |
| if randomize_seed: | |
| seed = random.randint(0, MAX_SEED) | |
| encoded_person_img = cv2.imencode('.jpg', cv2.cvtColor(person_img, cv2.COLOR_RGB2BGR))[1].tobytes() | |
| encoded_person_img = base64.b64encode(encoded_person_img).decode('utf-8') | |
| encoded_garment_img = cv2.imencode('.jpg', cv2.cvtColor(garment_img, cv2.COLOR_RGB2BGR))[1].tobytes() | |
| encoded_garment_img = base64.b64encode(encoded_garment_img).decode('utf-8') | |
| url = "http://" + os.environ['tryon_url'] + "Submit" | |
| token = os.environ['token'] | |
| cookie = os.environ['Cookie'] | |
| referer = os.environ['referer'] | |
| headers = {'Content-Type': 'application/json', 'token': token, 'Cookie': cookie, 'referer': referer} | |
| data = { | |
| "clothImage": encoded_garment_img, | |
| "humanImage": encoded_person_img, | |
| "seed": seed | |
| } | |
| try: | |
| response = requests.post(url, headers=headers, data=json.dumps(data), timeout=50) | |
| if response.status_code == 200: | |
| result = response.json()['result'] | |
| status = result['status'] | |
| if status == "success": | |
| uuid = result['result'] | |
| except Exception as err: | |
| print(f"Post Exception Error: {err}") | |
| raise gr.Error("Too many users, please try again later") | |
| post_end_time = time.time() | |
| print(f"post time used: {post_end_time-post_start_time}") | |
| get_start_time = time.time() | |
| time.sleep(9) | |
| Max_Retry = 12 | |
| result_img = None | |
| info = "" | |
| err_log = "" | |
| for i in range(Max_Retry): | |
| try: | |
| url = "http://" + os.environ['tryon_url'] + "Query?taskId=" + uuid | |
| response = requests.get(url, headers=headers, timeout=20) | |
| if response.status_code == 200: | |
| result = response.json()['result'] | |
| status = result['status'] | |
| if status == "success": | |
| result = base64.b64decode(result['result']) | |
| result_np = np.frombuffer(result, np.uint8) | |
| result_img = cv2.imdecode(result_np, cv2.IMREAD_UNCHANGED) | |
| result_img = cv2.cvtColor(result_img, cv2.COLOR_RGB2BGR) | |
| info = "Success" | |
| break | |
| elif status == "error": | |
| err_log = f"Status is Error" | |
| info = "Error" | |
| break | |
| else: | |
| err_log = "URL error, please contact the admin" | |
| info = "URL error, please contact the admin" | |
| break | |
| except requests.exceptions.ReadTimeout: | |
| err_log = "Http Timeout" | |
| info = "Http Timeout, please try again later" | |
| except Exception as err: | |
| err_log = f"Get Exception Error: {err}" | |
| time.sleep(1) | |
| get_end_time = time.time() | |
| print(f"get time used: {get_end_time-get_start_time}") | |
| print(f"all time used: {get_end_time-get_start_time+post_end_time-post_start_time}") | |
| if info == "": | |
| err_log = f"No image after {Max_Retry} retries" | |
| info = "Too many users, please try again later" | |
| if info != "Success": | |
| print(f"Error Log: {err_log}") | |
| gr.Warning("Too many users, please try again later") | |
| return result_img, seed, info | |
| def start_tryon(person_img, garment_img, seed, randomize_seed): | |
| start_time = time.time() | |
| if person_img is None or garment_img is None: | |
| return None, None, "Empty image" | |
| if randomize_seed: | |
| seed = random.randint(0, MAX_SEED) | |
| encoded_person_img = cv2.imencode('.jpg', cv2.cvtColor(person_img, cv2.COLOR_RGB2BGR))[1].tobytes() | |
| encoded_person_img = base64.b64encode(encoded_person_img).decode('utf-8') | |
| encoded_garment_img = cv2.imencode('.jpg', cv2.cvtColor(garment_img, cv2.COLOR_RGB2BGR))[1].tobytes() | |
| encoded_garment_img = base64.b64encode(encoded_garment_img).decode('utf-8') | |
| url = "http://" + os.environ['tryon_url'] | |
| token = os.environ['token'] | |
| cookie = os.environ['Cookie'] | |
| referer = os.environ['referer'] | |
| headers = {'Content-Type': 'application/json', 'token': token, 'Cookie': cookie, 'referer': referer} | |
| data = { | |
| "clothImage": encoded_garment_img, | |
| "humanImage": encoded_person_img, | |
| "seed": seed | |
| } | |
| result_img = None | |
| try: | |
| session = requests.Session() | |
| response = session.post(url, headers=headers, data=json.dumps(data), timeout=60) | |
| print("response code", response.status_code) | |
| if response.status_code == 200: | |
| result = response.json()['result'] | |
| status = result['status'] | |
| if status == "success": | |
| result = base64.b64decode(result['result']) | |
| result_np = np.frombuffer(result, np.uint8) | |
| result_img = cv2.imdecode(result_np, cv2.IMREAD_UNCHANGED) | |
| result_img = cv2.cvtColor(result_img, cv2.COLOR_RGB2BGR) | |
| info = "Success" | |
| else: | |
| info = "Try again later" | |
| else: | |
| print(response.text) | |
| info = "URL error, please contact the admin" | |
| except requests.exceptions.ReadTimeout: | |
| print("timeout") | |
| info = "Too many users, 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" | |
| end_time = time.time() | |
| print(f"time used: {end_time-start_time}") | |
| return result_img, seed, info | |
| def capture_person_photo(webcam_image): | |
| """Process captured person photo from webcam""" | |
| if webcam_image is None: | |
| gr.Warning("No image captured from camera") | |
| return None | |
| return webcam_image | |
| def capture_garment_photo(webcam_image): | |
| """Process captured garment photo from webcam""" | |
| if webcam_image is None: | |
| gr.Warning("No image captured from camera") | |
| return None | |
| return webcam_image | |
| def clear_person_image(): | |
| """Clear the person image""" | |
| return None | |
| def clear_garment_image(): | |
| """Clear the garment image""" | |
| return None | |
| def switch_to_upload_person(): | |
| """Switch to upload mode for person image""" | |
| return gr.update(visible=True), gr.update(visible=False) | |
| def switch_to_camera_person(): | |
| """Switch to camera mode for person image""" | |
| return gr.update(visible=False), gr.update(visible=True) | |
| def switch_to_upload_garment(): | |
| """Switch to upload mode for garment image""" | |
| return gr.update(visible=True), gr.update(visible=False) | |
| def switch_to_camera_garment(): | |
| """Switch to camera mode for garment image""" | |
| return gr.update(visible=False), gr.update(visible=True) | |
| MAX_SEED = 999999 | |
| example_path = os.path.join(os.path.dirname(__file__), 'assets') | |
| # Check if assets directory exists, if not create dummy lists | |
| if os.path.exists(example_path): | |
| garm_list = os.listdir(os.path.join(example_path, "cloth")) if os.path.exists(os.path.join(example_path, "cloth")) else [] | |
| 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")) if os.path.exists(os.path.join(example_path, "human")) else [] | |
| human_list_path = [os.path.join(example_path, "human", human) for human in human_list] | |
| else: | |
| garm_list_path = [] | |
| human_list_path = [] | |
| css = """ | |
| #col-left { | |
| margin: 0 auto; | |
| max-width: 450px; | |
| } | |
| #col-mid { | |
| margin: 0 auto; | |
| max-width: 450px; | |
| } | |
| #col-right { | |
| margin: 0 auto; | |
| max-width: 450px; | |
| } | |
| #col-showcase { | |
| margin: 0 auto; | |
| max-width: 1100px; | |
| } | |
| #button { | |
| color: blue; | |
| } | |
| .camera-section { | |
| border: 2px dashed #ccc; | |
| border-radius: 10px; | |
| padding: 10px; | |
| margin: 5px 0; | |
| } | |
| .mode-buttons { | |
| display: flex; | |
| gap: 10px; | |
| margin-bottom: 10px; | |
| } | |
| """ | |
| def load_description(fp): | |
| """Load description from file if it exists, otherwise return default""" | |
| try: | |
| with open(fp, 'r', encoding='utf-8') as f: | |
| content = f.read() | |
| return content | |
| except FileNotFoundError: | |
| return """ | |
| # π― Virtual Try-On Application | |
| **Experience the future of fashion with AI-powered virtual try-on technology!** | |
| Upload or capture photos of yourself and garments to see how they look together. | |
| """ | |
| def change_imgs(image1, image2): | |
| return image1, image2 | |
| with gr.Blocks(css=css) as Tryon: | |
| gr.HTML(load_description("assets/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. Get 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. Get 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. Generate Try-On Result | |
| </div> | |
| </div> | |
| """) | |
| with gr.Row(): | |
| # Person Image Column | |
| with gr.Column(elem_id="col-left"): | |
| # Mode selection buttons for person | |
| with gr.Row(elem_classes="mode-buttons"): | |
| upload_person_btn = gr.Button("π Upload Photo", variant="secondary", size="sm") | |
| camera_person_btn = gr.Button("π· Take Photo", variant="secondary", size="sm") | |
| clear_person_btn = gr.Button("ποΈ Clear", variant="secondary", size="sm") | |
| # Upload interface for person (visible by default) | |
| with gr.Group(visible=True) as person_upload_group: | |
| person_img_upload = gr.Image( | |
| label="Person Image (Upload)", | |
| sources=['upload'], | |
| type="numpy", | |
| height=400 | |
| ) | |
| # Camera interface for person (hidden by default) | |
| with gr.Group(visible=False, elem_classes="camera-section") as person_camera_group: | |
| person_img_camera = gr.Image( | |
| label="Person Image (Camera)", | |
| sources=['webcam'], | |
| type="numpy", | |
| height=400 | |
| ) | |
| capture_person_btn = gr.Button("πΈ Capture Person Photo", variant="primary") | |
| # Combined person image state | |
| person_img_final = gr.State() | |
| # Examples for person images | |
| if human_list_path: | |
| example_person = gr.Examples( | |
| inputs=person_img_upload, | |
| examples_per_page=8, | |
| examples=human_list_path, | |
| label="Example Person Images" | |
| ) | |
| # Garment Image Column | |
| with gr.Column(elem_id="col-mid"): | |
| # Mode selection buttons for garment | |
| with gr.Row(elem_classes="mode-buttons"): | |
| upload_garment_btn = gr.Button("π Upload Photo", variant="secondary", size="sm") | |
| camera_garment_btn = gr.Button("π· Take Photo", variant="secondary", size="sm") | |
| clear_garment_btn = gr.Button("ποΈ Clear", variant="secondary", size="sm") | |
| # Upload interface for garment (visible by default) | |
| with gr.Group(visible=True) as garment_upload_group: | |
| garment_img_upload = gr.Image( | |
| label="Garment Image (Upload)", | |
| sources=['upload'], | |
| type="numpy", | |
| height=400 | |
| ) | |
| # Camera interface for garment (hidden by default) | |
| with gr.Group(visible=False, elem_classes="camera-section") as garment_camera_group: | |
| garment_img_camera = gr.Image( | |
| label="Garment Image (Camera)", | |
| sources=['webcam'], | |
| type="numpy", | |
| height=400 | |
| ) | |
| capture_garment_btn = gr.Button("πΈ Capture Garment Photo", variant="primary") | |
| # Combined garment image state | |
| garment_img_final = gr.State() | |
| # Examples for garment images | |
| if garm_list_path: | |
| example_garment = gr.Examples( | |
| inputs=garment_img_upload, | |
| examples_per_page=8, | |
| examples=garm_list_path, | |
| label="Example Garment Images" | |
| ) | |
| # Results Column | |
| with gr.Column(elem_id="col-right"): | |
| image_out = gr.Image(label="π― Try-On Result", show_share_button=False, height=400) | |
| 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="Status") | |
| # Main try-on button | |
| tryon_button = gr.Button("π Generate Try-On", variant="primary", size="lg") | |
| # Event handlers for person image mode switching | |
| upload_person_btn.click( | |
| switch_to_upload_person, | |
| outputs=[person_upload_group, person_camera_group] | |
| ) | |
| camera_person_btn.click( | |
| switch_to_camera_person, | |
| outputs=[person_upload_group, person_camera_group] | |
| ) | |
| clear_person_btn.click( | |
| clear_person_image, | |
| outputs=[person_img_upload] | |
| ) | |
| # Event handlers for garment image mode switching | |
| upload_garment_btn.click( | |
| switch_to_upload_garment, | |
| outputs=[garment_upload_group, garment_camera_group] | |
| ) | |
| camera_garment_btn.click( | |
| switch_to_camera_garment, | |
| outputs=[garment_upload_group, garment_camera_group] | |
| ) | |
| clear_garment_btn.click( | |
| clear_garment_image, | |
| outputs=[garment_img_upload] | |
| ) | |
| # Capture button handlers | |
| capture_person_btn.click( | |
| capture_person_photo, | |
| inputs=[person_img_camera], | |
| outputs=[person_img_final] | |
| ) | |
| capture_garment_btn.click( | |
| capture_garment_photo, | |
| inputs=[garment_img_camera], | |
| outputs=[garment_img_final] | |
| ) | |
| # Function to get the current person image | |
| def get_current_person_image(upload_img, camera_img, final_img): | |
| if final_img is not None: | |
| return final_img | |
| elif upload_img is not None: | |
| return upload_img | |
| elif camera_img is not None: | |
| return camera_img | |
| return None | |
| # Function to get the current garment image | |
| def get_current_garment_image(upload_img, camera_img, final_img): | |
| if final_img is not None: | |
| return final_img | |
| elif upload_img is not None: | |
| return upload_img | |
| elif camera_img is not None: | |
| return camera_img | |
| return None | |
| # Modified try-on function to handle multiple image sources | |
| def run_tryon(person_upload, person_camera, person_final, | |
| garment_upload, garment_camera, garment_final, | |
| seed, randomize_seed): | |
| # Get the current person image | |
| person_img = get_current_person_image(person_upload, person_camera, person_final) | |
| # Get the current garment image | |
| garment_img = get_current_garment_image(garment_upload, garment_camera, garment_final) | |
| # Run the try-on process | |
| return tryon(person_img, garment_img, seed, randomize_seed) | |
| # Main try-on button click handler | |
| tryon_button.click( | |
| fn=run_tryon, | |
| inputs=[ | |
| person_img_upload, person_img_camera, person_img_final, | |
| garment_img_upload, garment_img_camera, garment_img_final, | |
| seed, randomize_seed | |
| ], | |
| outputs=[image_out, seed_used, result_info], | |
| api_name=False, | |
| concurrency_limit=45 | |
| ) | |
| # Showcase section | |
| 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; margin-top: 30px;"> | |
| <div> | |
| π Virtual Try-On Examples | |
| <br><br> | |
| <em>See how different garments look on various models</em> | |
| </div> | |
| </div> | |
| """) | |
| # Only show examples if they exist | |
| if os.path.exists("assets/examples"): | |
| 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=[person_img_upload, garment_img_upload, image_out], | |
| label="Example Try-On Results" | |
| ) | |
| # Launch the app | |
| if __name__ == "__main__": | |
| Tryon.queue(api_open=False).launch( | |
| show_api=False, | |
| share=False, | |
| server_name="0.0.0.0", | |
| server_port=7860 | |
| ) |