diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..52b9baab12fa494f601c95a02f3df0389cb7407f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,35 +1,39 @@ -*.7z filter=lfs diff=lfs merge=lfs -text -*.arrow filter=lfs diff=lfs merge=lfs -text -*.bin filter=lfs diff=lfs merge=lfs -text -*.bz2 filter=lfs diff=lfs merge=lfs -text -*.ckpt filter=lfs diff=lfs merge=lfs -text -*.ftz filter=lfs diff=lfs merge=lfs -text -*.gz filter=lfs diff=lfs merge=lfs -text -*.h5 filter=lfs diff=lfs merge=lfs -text -*.joblib filter=lfs diff=lfs merge=lfs -text -*.lfs.* filter=lfs diff=lfs merge=lfs -text -*.mlmodel filter=lfs diff=lfs merge=lfs -text -*.model filter=lfs diff=lfs merge=lfs -text -*.msgpack filter=lfs diff=lfs merge=lfs -text -*.npy filter=lfs diff=lfs merge=lfs -text -*.npz filter=lfs diff=lfs merge=lfs -text -*.onnx filter=lfs diff=lfs merge=lfs -text -*.ot filter=lfs diff=lfs merge=lfs -text -*.parquet filter=lfs diff=lfs merge=lfs -text -*.pb filter=lfs diff=lfs merge=lfs -text -*.pickle filter=lfs diff=lfs merge=lfs -text -*.pkl filter=lfs diff=lfs merge=lfs -text -*.pt filter=lfs diff=lfs merge=lfs -text -*.pth filter=lfs diff=lfs merge=lfs -text -*.rar filter=lfs diff=lfs merge=lfs -text -*.safetensors filter=lfs diff=lfs merge=lfs -text -saved_model/**/* filter=lfs diff=lfs merge=lfs -text -*.tar.* filter=lfs diff=lfs merge=lfs -text -*.tar filter=lfs diff=lfs merge=lfs -text -*.tflite filter=lfs diff=lfs merge=lfs -text -*.tgz filter=lfs diff=lfs merge=lfs -text -*.wasm filter=lfs diff=lfs merge=lfs -text -*.xz filter=lfs diff=lfs merge=lfs -text -*.zip filter=lfs diff=lfs merge=lfs -text -*.zst filter=lfs diff=lfs merge=lfs -text -*tfevents* filter=lfs diff=lfs merge=lfs -text +*.7z filter=lfs diff=lfs merge=lfs -text +*.arrow filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.ckpt filter=lfs diff=lfs merge=lfs -text +*.ftz filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.h5 filter=lfs diff=lfs merge=lfs -text +*.joblib filter=lfs diff=lfs merge=lfs -text +*.lfs.* filter=lfs diff=lfs merge=lfs -text +*.mlmodel filter=lfs diff=lfs merge=lfs -text +*.model filter=lfs diff=lfs merge=lfs -text +*.msgpack filter=lfs diff=lfs merge=lfs -text +*.npy filter=lfs diff=lfs merge=lfs -text +*.npz filter=lfs diff=lfs merge=lfs -text +*.onnx filter=lfs diff=lfs merge=lfs -text +*.ot filter=lfs diff=lfs merge=lfs -text +*.parquet filter=lfs diff=lfs merge=lfs -text +*.pb filter=lfs diff=lfs merge=lfs -text +*.pickle filter=lfs diff=lfs merge=lfs -text +*.pkl filter=lfs diff=lfs merge=lfs -text +*.pt filter=lfs diff=lfs merge=lfs -text +*.pth filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.safetensors filter=lfs diff=lfs merge=lfs -text +saved_model/**/* filter=lfs diff=lfs merge=lfs -text +*.tar.* filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tflite filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.wasm filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text +*tfevents* filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.jpeg filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.webp filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..f50e644583e11673516518b64271cdb35e6a8edb --- /dev/null +++ b/.gitignore @@ -0,0 +1,149 @@ +debug/ +testing/output/ + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# PyCharm +.idea + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# MacOS filesystem +.DS_Store + +.gradio \ No newline at end of file diff --git a/README.md b/README.md index 700234c0e23f2d14b352797020f836933e8e3194..f575a827c341e22953fa6fe1247d205950037343 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,29 @@ ---- -title: ISSATM VTO -emoji: 👁 -colorFrom: red -colorTo: gray -sdk: gradio -sdk_version: 5.6.0 -app_file: app.py -pinned: false ---- - -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference +--- +title: Virtual Try-On Diffusion [VTON-D] +emoji: 👗 +colorFrom: indigo +colorTo: purple +sdk: gradio +sdk_version: 5.6.0 +app_file: app.py +pinned: false +short_description: Diffusion-based multi-modal virtual try-on pipeline demo +tags: + - virtual try-on + - vton + - clothing transfer + - diffusion + - img2img + - txt2img +--- + +# Virtual Try-On Diffusion [VTON-D] by Texel.Moda + +Virtual Try-On Diffusion [VTON-D] by [Texel.Moda](https://texelmoda.com/) is a custom diffusion-based pipeline for fast +and flexible multi-modal virtual try-on. Clothing, avatar and background can be specified by reference images or text +prompts allowing for clothing transfer, avatar replacement, fashion image generation and other virtual try-on related +tasks. + +This API is available [through the RapidAPI Hub](https://rapidapi.com/texelmoda-texelmoda-apis/api/try-on-diffusion). +Additionally, you can find the extensive API documentation +[here](https://huggingface.co/spaces/texelmoda/try-on-diffusion/blob/main/docs/API.md). diff --git a/app.py b/app.py new file mode 100644 index 0000000000000000000000000000000000000000..5e6f82aac4ad636f65f154e4146afe10149090ed --- /dev/null +++ b/app.py @@ -0,0 +1,291 @@ +import logging +import gradio as gr +import numpy as np +import cv2 +import os +import base64 + +from try_on_diffusion_client import TryOnDiffusionClient + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)s %(thread)-8s %(name)-16s %(levelname)-8s %(message)s" +LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S" + +EXAMPLE_PATH = os.path.join(os.path.dirname(__file__), "examples") + +API_URL = os.getenv("TRY_ON_DIFFUSION_DEMO_API_URL", "http://localhost:8000") +API_KEY = os.getenv("TRY_ON_DIFFUSION_DEMO_API_KEY", "") + +SHOW_RAPIDAPI_LINK = os.getenv("TRY_ON_DIFFUSION_DEMO_SHOW_RAPIDAPI_LINK", "1") == "1" + +CONCURRENCY_LIMIT = int(os.getenv("TRY_ON_DIFFUSION_DEMO_CONCURRENCY_LIMIT", "2")) + +logging.basicConfig(level=LOG_LEVEL, format=LOG_FORMAT, datefmt=LOG_DATE_FORMAT) + +client = TryOnDiffusionClient(base_url=API_URL, api_key=API_KEY) + + +def get_image_base64(file_name: str) -> str: + _, ext = os.path.splitext(file_name.lower()) + + content_type = "image/jpeg" + + if ext == ".png": + content_type = "image/png" + elif ext == ".webp": + content_type = "image/webp" + elif ext == ".gif": + content_type = "image/gif" + + with open(file_name, "rb") as f: + return f"data:{content_type};base64," + base64.b64encode(f.read()).decode("utf-8") + + +def get_examples(example_dir: str) -> list[str]: + file_list = [f for f in os.listdir(os.path.join(EXAMPLE_PATH, example_dir)) if f.endswith(".jpg")] + file_list.sort() + + return [os.path.join(EXAMPLE_PATH, example_dir, f) for f in file_list] + + +def try_on( + clothing_image: np.ndarray = None, + clothing_prompt: str = None, + avatar_image: np.ndarray = None, + avatar_prompt: str = None, + avatar_sex: str = None, + background_image: np.ndarray = None, + background_prompt: str = None, + seed: int = -1, +) -> tuple: + result = client.try_on_file( + clothing_image=cv2.cvtColor(clothing_image, cv2.COLOR_RGB2BGR) if clothing_image is not None else None, + clothing_prompt=clothing_prompt, + avatar_image=cv2.cvtColor(avatar_image, cv2.COLOR_RGB2BGR) if avatar_image is not None else None, + avatar_prompt=avatar_prompt, + avatar_sex=avatar_sex if avatar_sex in ["male", "female"] else None, + background_image=cv2.cvtColor(background_image, cv2.COLOR_RGB2BGR) if background_image is not None else None, + background_prompt=background_prompt, + seed=seed, + ) + + if result.status_code == 200: + return cv2.cvtColor(result.image, cv2.COLOR_BGR2RGB), f"

Success

Seed: {result.seed}

" + else: + error_message = f"

Error {result.status_code}

" + + if result.error_details is not None: + error_message += f"

{result.error_details}

" + + return None, error_message + + +with gr.Blocks(theme=gr.themes.Soft(), delete_cache=(3600, 3600)) as app: + gr.HTML( + f""" +
+ + Texel.Moda + +

Virtual Try-On Diffusion

+
+
+

+ Virtual Try-On Diffusion [VTON-D] by Texel.Moda is a + custom diffusion-based pipeline for fast and flexible multi-modal virtual try-on. + Clothing, avatar and background can be specified by reference images or text prompts allowing for clothing + transfer, avatar replacement, fashion image generation and other virtual try-on related tasks. + """ + ) + + if SHOW_RAPIDAPI_LINK: + gr.Button( + value="Check out the API @ RapidAPI.com", + link="https://rapidapi.com/texelmoda-texelmoda-apis/api/try-on-diffusion", + icon="https://files.readme.io/9336831-small-rapid-logo-favicon.png", + ) + + gr.HTML( + """ +

+ API Documentation +
+ """ + ) + + gr.HTML("

") + + with gr.Row(): + with gr.Column(): + gr.HTML( + """ +

Clothing

+

+ Clothing may be specified with a reference image or a text prompt. + For more exotic use cases image and prompt can be also used together. + If both image and prompt are empty the model will generate random clothing. +

+

+ """ + ) + + with gr.Tab("Image"): + clothing_image = gr.Image(label="Clothing Image", sources=["upload"], type="numpy") + + clothing_image_examples = gr.Examples( + inputs=clothing_image, examples_per_page=12, examples=get_examples("clothing") + ) + + with gr.Tab("Prompt"): + clothing_prompt = gr.TextArea( + label="Clothing Prompt", + info='Compel weighting syntax is supported.', + ) + + clothing_prompt_examples = gr.Examples( + inputs=clothing_prompt, + examples_per_page=8, + examples=[ + "a sheer blue sleeveless mini dress", + "a beige woolen sweater and white pleated skirt", + "a black leather jacket and dark blue slim-fit jeans", + "a floral pattern blouse and leggings", + "a paisley pattern purple shirt and beige chinos", + "a striped white and blue polo shirt and blue jeans", + "a colorful t-shirt and black shorts", + "a checked pattern shirt and dark blue cargo pants", + ], + ) + + with gr.Column(): + gr.HTML( + """ +

Avatar

+

+ Avatar may be specified with a subject photo or a text prompt. + Latter can be used, for example, to replace person while preserving clothing. + For more exotic use cases image and prompt can be also used together. + If both image and prompt are empty the model will generate random avatars. +

+ """ + ) + + with gr.Tab("Image"): + avatar_image = gr.Image(label="Avatar Image", sources=["upload"], type="numpy") + + avatar_image_examples = gr.Examples( + inputs=avatar_image, + examples_per_page=12, + examples=get_examples("avatar"), + ) + + with gr.Tab("Prompt"): + avatar_prompt = gr.TextArea( + label="Avatar Prompt", + info='Compel weighting syntax is supported.', + ) + + avatar_prompt_examples = gr.Examples( + inputs=avatar_prompt, + examples_per_page=8, + examples=[ + "a beautiful blond girl with long hair", + "a cute redhead girl with freckles", + "a plus size female model wearing sunglasses", + "a woman with dark hair and blue eyes", + "a fit man with dark beard and blue eyes", + "a young blond man posing for a photo", + "a gentleman with beard and mustache", + "a plus size man walking", + ], + ) + + avatar_sex = gr.Dropdown( + label="Avatar Sex", + choices=[("Auto", ""), ("Male", "male"), ("Female", "female")], + value="", + info="Avatar sex selector can be used to enforce a specific sex of the avatar.", + ) + + with gr.Column(): + gr.HTML( + """ +

Background

+

+ Replacing background is optional. + Background may be specified with a reference image or a text prompt. + If omitted original avatar background will be preserved. +


+

+ """ + ) + + with gr.Tab("Image"): + background_image = gr.Image(label="Background Image", sources=["upload"], type="numpy") + + background_image_examples = gr.Examples( + inputs=background_image, examples_per_page=12, examples=get_examples("background") + ) + + with gr.Tab("Prompt"): + background_prompt = gr.TextArea( + label="Background Prompt", + info='Compel weighting syntax is supported.', + ) + + background_prompt_examples = gr.Examples( + inputs=background_prompt, + examples_per_page=8, + examples=[ + "in an autumn park", + "in front of a brick wall", + "near an old tree", + "on a busy city street", + "in front of a staircase", + "on an ocean beach with palm trees", + "in a shopping mall", + "in a modern office", + ], + ) + + with gr.Column(): + gr.HTML( + """ +

Generation

+ """ + ) + + seed = gr.Number( + label="Seed", + value=-1, + minimum=-1, + info="Seed used for generation, specify -1 for random seed for each generation.", + ) + + generate_button = gr.Button(value="Generate", variant="primary") + + result_image = gr.Image(label="Result", show_share_button=False, format="jpeg") + result_details = gr.HTML(label="Details") + + generate_button.click( + fn=try_on, + inputs=[ + clothing_image, + clothing_prompt, + avatar_image, + avatar_prompt, + avatar_sex, + background_image, + background_prompt, + seed, + ], + outputs=[result_image, result_details], + api_name=False, + concurrency_limit=CONCURRENCY_LIMIT, + ) + + app.title = "Virtual Try-On Diffusion by Texel.Moda" + + +if __name__ == "__main__": + app.queue(api_open=False).launch(show_api=False) diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 0000000000000000000000000000000000000000..707d5b429be72f4695d26056e3526e50b782f659 --- /dev/null +++ b/docs/API.md @@ -0,0 +1,341 @@ +# Virtual Try-On Diffusion API + + +* [Virtual Try-On Diffusion API](#virtual-try-on-diffusion-api) + * [Summary](#summary) + * [Consuming the API](#consuming-the-api) + * [Try-On Endpoints](#try-on-endpoints) + * [Try-On Input Parameters](#try-on-input-parameters) + * [Clothing image](#clothing-image) + * [Clothing prompt](#clothing-prompt) + * [Avatar image](#avatar-image) + * [Avatar prompt](#avatar-prompt) + * [Background image](#background-image) + * [Background prompt](#background-prompt) + * [Additional notes](#additional-notes) + * [Try-On Output](#try-on-output) + * [Response codes](#response-codes) + * [NSFW content](#nsfw-content) + * [Use Cases and Recipes](#use-cases-and-recipes) + * [Image-based virtual try-on](#image-based-virtual-try-on) + * [Image-based virtual try-on with background](#image-based-virtual-try-on-with-background) + * [Avatar from a text prompt](#avatar-from-a-text-prompt) + * [Clothing from a text prompt](#clothing-from-a-text-prompt) + * [Modifying avatar's body](#modifying-avatars-body) + * [Txt2Img](#txt2img) + * [Other creative possibilities](#other-creative-possibilities) + * [Performance](#performance) + * [Known Issues and Limitations](#known-issues-and-limitations) + + +## Summary + +Virtual Try-On Diffusion [VTON-D] by [Texel.Moda](https://texelmoda.com) is a custom diffusion-based pipeline for fast +and flexible multi-modal virtual try-on. Clothing, avatar and background can be specified by reference images or text +prompts allowing for clothing transfer, avatar replacement, fashion image generation and other virtual try-on related +tasks. Check out the [demo on Hugging Face](https://huggingface.co/spaces/texelmoda/try-on-diffusion) to try the API in +a user-friendly way. + +## Consuming the API + +The API is exposed through the RapidAPI Hub which manages API subscriptions, API keys, payments and other things. Please +refer to the [RapidAPI Documentation](https://docs.rapidapi.com/docs/consumer-quick-start-guide) to get started. + +Generally, in order to use an API you need to perform the following steps: +- Create a RapidAPI.com account. +- [Navigate to the API page](https://rapidapi.com/texelmoda-texelmoda-apis/api/try-on-diffusion) and subscribe to a + suitable pricing plan. We also provide a free BASIC plan with 100 API requests per month. +- Use the obtained RapidAPI key to authenticate (via the _X-RapidAPI-Key_ header) and use an API from any programming + language or tool you like. + +Example API call using cURL: +```shell +curl --request POST \ +--url https://try-on-diffusion.p.rapidapi.com/try-on-file \ +--header 'Content-Type: multipart/form-data' \ +--header 'x-rapidapi-host: try-on-diffusion.p.rapidapi.com' \ +--header 'x-rapidapi-key: ' \ +--form clothing_image=1.jpg \ +--form avatar_image=2.jpg +``` + +For a simple Python client implementation please see the +[Hugging Face demo application source](https://huggingface.co/spaces/texelmoda/try-on-diffusion/blob/main/try_on_diffusion_client.py). + +## Try-On Endpoints + +Try-On API consists of two endpoints that differ only in the method of passing reference images: + +- **POST** _/try-on-file_ - takes reference images as uploaded files in the request body (using multipart/form-data). + + +- **POST** _/try-on-url_ - takes reference images as image URLs in POST parameters. + +All image requirements, behavior and status codes are the same for both endpoints, choose the one that best suits your +application architecture. + +## Try-On Input Parameters + +All input parameters for the try-on endpoints are currently optional. Images and prompts serve as additional generation +conditions and can even be used in combination. Below is the short parameter summary with links to extended information +on certain parameters. + +List of input parameters for the **POST** _/try-on-file_ endpoint: + +| Parameter | Description | Required | +|-----------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------| +| [clothing_image](#clothing-image) | Clothing reference image in JPEG, PNG or WEBP format, maximum file size is 12 MB. | No | +| [clothing_prompt](#clothing-prompt) | Text prompt for clothing, can be used instead of an image. Compel weighting syntax is supported. Example: _red sleeveless mini dress_ | No | +| [avatar_image](#avatar-image) | Avatar image in JPEG, PNG or WEBP format, maximum file size is 12 MB. | No | +| avatar_sex | Avatar sex, either "male" or "female". Will be detected automatically, if left empty or omitted. Will enforce certain avatar sex if specified. | No | +| [avatar_prompt](#avatar-prompt) | Text prompt for the avatar, can be used instead of an image or with image to modify the avatar. Compel weighting syntax is supported. Example: _a gentleman with beard and mustache_ | No | +| [background_image](#background-image) | Optional background reference image in JPEG, PNG or WEBP format, maximum file size is 12 MB. Original avatar background is preserved if background is not specified. | No | +| [background_prompt](#background-prompt) | Optional background text prompt. Original avatar background is preserved if background is not specified. Example: _in an autumn park_ | No | +| seed | Seed for image generation. Default is -1 (random seed). Actual seed will also be output in the "X-Seed" response header. Example: _42_ | No | + +List of input parameters for the **POST** _/try-on-url_ endpoint: + +| Parameter | Description | Required | +|-------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------| +| [clothing_image_url](#clothing-image) | Clothing reference image URL. Image should be in JPEG, PNG or WEBP format, maximum file size is 12 MB. | No | +| [clothing_prompt](#clothing-prompt) | Text prompt for clothing, can be used instead of an image. Compel weighting syntax is supported. Example: _red sleeveless mini dress_ | No | +| [avatar_image_url](#avatar-image) | Avatar image URL. Image should be in JPEG, PNG or WEBP format, maximum file size is 12 MB. | No | +| avatar_sex | Avatar sex, either "male" or "female". Will be detected automatically, if left empty or omitted. Will enforce certain avatar sex if specified. | No | +| [avatar_prompt](#avatar-prompt) | Text prompt for the avatar, can be used instead of an image or with image to modify the avatar. Compel weighting syntax is supported. Example: _a gentleman with beard and mustache_ | No | +| [background_image_url](#background-image) | Optional background reference image URL. Image should be in JPEG, PNG or WEBP format, maximum file size is 12 MB. Original avatar background is preserved if background is not specified. | No | +| [background_prompt](#background-prompt) | Optional background text prompt. Original avatar background is preserved if background is not specified. Example: _in an autumn park_ | No | +| seed | Seed for image generation. Default is -1 (random seed). Actual seed will also be output in the "X-Seed" response header. Example: _42_ | No | + +### Clothing image + +For best results clothing reference images should meet a number of requirements: + +- File format: **JPEG**, **PNG** or **WEBP** +- Maximum file size: **12 MB** +- Minimum image size: **256x256** +- Recommended image size: **768x1024 and above** +- Clothing should be **dressed on a person**. Some flat lay clothing photos might work, but currently it's not guaranteed +- **Single person** on the image (though multiple persons might also work) +- **Frontal** photo, though some degree of rotation is fine +- **Good lighting** conditions and **high image quality** as it directly affects the result +- **Minimal occlusion** by hair, hands or accessories + +To summarize: the better is the clothing image the better is the final result. + +Examples of good clothing images: + +| | | | | +|------------------------------------------------------|------------------------------------------------------|------------------------------------------------------|------------------------------------------------------| + +### Clothing prompt + +Instead of a clothing image you can use text prompt to describe the garment. Short and clear prompts work best. +Additionally, [Compel weighting syntax](https://github.com/damian0815/compel/blob/main/doc/syntax.md) is supported to +increase or decrease weight of certain tokens. Examples: +- _a sheer blue sleeveless mini dress_ +- _a beige woolen sweater and white pleated skirt_ +- _a black leather jacket and dark blue slim-fit jeans_ +- _a floral pattern blouse and leggings_ +- _a colorful+++ t-shirt and black shorts_ + +### Avatar image + +Avatar images should also meet a some requirements: + +- File format: **JPEG**, **PNG** or **WEBP** +- Maximum file size: **12 MB** +- Minimum image size: **256x256** +- Recommended image size: **768x1024 and above** +- **Single person** on the image (though multiple persons might also work) +- **Frontal** photo, though some degree of rotation is fine +- **Good lighting** conditions and **high image quality** + +Examples of good avatar images: + +| | | | | +|----------------------------------------------------|----------------------------------------------------|----------------------------------------------------|----------------------------------------------------| + +### Avatar prompt + +Instead of an avatar image you can use text prompt to describe the person. Short and clear prompts work best. +Additionally, [Compel weighting syntax](https://github.com/damian0815/compel/blob/main/doc/syntax.md) is supported to +increase or decrease weight of certain tokens. Examples: +- _a beautiful blond girl with long hair_ +- _a cute redhead girl with freckles_ +- _a (plus size)++ female model wearing sunglasses_ +- _a fit man with dark beard and blue eyes_ +- _a gentleman with beard and mustache_ + +### Background image + +Background images are used to extract high-level background features only and serve as a reference (and not exact +background). Below are basic image requirements: + +- File format: **JPEG**, **PNG** or **WEBP** +- Maximum file size: **12 MB** +- Recommended image size: **256x256 and above** + +Examples of background images: + +| | | | | +|--------------------------------------------------------|--------------------------------------------------------|--------------------------------------------------------|--------------------------------------------------------| + +### Background prompt + +Instead of a background image you can use text prompt to describe the background. Short and clear prompts work best. +Additionally, [Compel weighting syntax](https://github.com/damian0815/compel/blob/main/doc/syntax.md) is supported to +increase or decrease weight of certain tokens. Examples: +- _in an autumn park_ +- _in front of a brick wall_ +- _on an ocean beach with (palm trees)++_ +- _in a shopping mall_ +- _in a modern office_ + +### Additional notes + +We use the "same-crop" approach for clothing and avatar images: images will be cropped roughly the same way (using pose +estimation), so we don't have to add too much new information (e.g. assume lower body clothing). So, if you use only a +photo of an upper body clothing the result will also be cropped the same way regardless of the avatar image (and the +other way around): + +| Clothing Image | Avatar Image | Result Image | +|------------------------------------------------------|-----------------------------------------------------|--------------------------------------------------------| +| | | | +| | | | + +## Try-On Output + +### Response codes + +HTTP status code is used as a high-level response status. In case of a successful API call HTTP code 200 will be +returned and response body will contain a resulting JPEG image with the maximum size of 768x1024 pixels. Response +will also have the "X-Seed" header set that should contain the actual seed used for image generation (for +reproducibility). Other status codes (not 200) indicate unsuccessful request, see the table below for additional +details: + +| Response Code | Content-Type | Headers | Description | Example | +|:-------------:|:------------------:|:--------------:|-----------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------:| +| **200** | image/jpeg | X-Seed: {seed} | Successful API call. Response body contains the resulting image in JPEG format. | | +| **400** | application/json | | Bad request: at least one of request parameters is invalid. Response body should contain additional error details in JSON format. | { "detail": "Invalid upload file type: application/x-zip-compressed" } | +| **403** | application/json | | Indicates authentication issue (e.g. invalid API key). | | +| **422** | application/json | | Request validation error. Response body should contain error details in JSON format. | { "detail": [ { "loc": [ "string", 0], "msg": "string", "type": "string" } ] } | +| **429** | | | Too many requests. Might be triggered by the RapidAPI proxy in case of reaching maximum request rate or API call limit. | | +| **500** | | | Indicates an internal server error, might not have any details. | | + +### NSFW content + +We use NSFW content checker to ensure we don't output inappropriate images. If potential NSFW content is detected in the +generated image, the API will return HTTP status code 400 with a corresponding error message in JSON response. + +## Use Cases and Recipes + +Our Virtual Try-On API offers a flexible way to specify clothing, avatar and background, which makes it possible to not +only perform a classic task of virtual try-on, but also generate entirely new images or alter existing images in some +interesting aspects. Feel free to try and explore! + +In all the examples below all unmentioned inputs are assumed to be empty. + +### Image-based virtual try-on + +The most common use case is to transfer clothing from one photo (e.g. from a product page) to another photo (e.g. +user avatar) while maintaining the avatar and the background. + +| Clothing Image | Avatar Image | Result Image | +|------------------------------------------------------|----------------------------------------------------|----------------------------------------------------------| +| | | | + +### Image-based virtual try-on with background + +Additionally, it's possible to replace the avatar background with a reference image or a text prompt. + +| Clothing Image | Avatar Image | Background Image | Result Image | +|------------------------------------------------------|----------------------------------------------------|--------------------------------------------------------|---------------------------------------------------------------------| +| | | | | + +And with a text prompt for the background: + +| Clothing Image | Avatar Image | Background Prompt | Result Image | +|------------------------------------------------------|----------------------------------------------------|------------------------------|---------------------------------------------------------------------| +| | | in front of a snowy mountain | | + +### Avatar from a text prompt + +It's possible to replace the person on the clothing image with an avatar, described in a text prompt. Background will be +changed as well and will be a random one if not specified: + +| Clothing Image | Avatar Prompt | Background Prompt | Result Image | +|------------------------------------------------------|--------------------------------------------|--------------------|------------------------------------------------------------| +| | a beautiful blond girl with long hair | | | +| | a gentleman with a long beard and mustache | near a fireplace | | + +You may also experiment with avatar prompts for more interesting results: + +| Clothing Image | Avatar Prompt | Background Prompt | Result Image | +|------------------------------------------------------|---------------------|-----------------------|------------------------------------------------------------| +| | (iron man mask)+++ | in the Sahara Desert | | + +### Clothing from a text prompt + +Similarly, you can specify clothing with a text prompt while providing an avatar image: + +| Clothing Prompt | Avatar Image | Result Image | +|-------------------------------------|----------------------------------------------------|--------------------------------------------------------------| +| a sheer blue sleeveless mini dress | | | +| a colorful t-shirt and black shorts | | | + +### Modifying avatar's body + +If you specify clothing and avatar images to be the same while providing an avatar prompt it's possible to change +avatar's body proportions. Note that it may require using additional term weighting to achieve stronger changes. + +| Clothing Image | Avatar Image | Avatar Prompt | Result Image | +|------------------------------------------------------|------------------------------------------------------|-------------------------------|------------------------------------------------------------------| +| | | a (plus size)+ woman | | +| | | a (muscular bodybuilder)+++++ | | + +### Txt2Img + +As our diffusion model was fine-tuned to produce people wearing various clothing, it can better follow a clothing prompt +and output realistic people and garments: + +| Clothing Prompt | Avatar Prompt | Background Prompt | Result Image | +|-------------------------------------------------|--------------------------------|------------------------|------------------------------------------------------| +| a paisley pattern purple shirt and beige chinos | a fit man with dark beard | plain white background | | +| a white polka dot pattern dress | a beautiful petite blond woman | on a yacht | | + +### Other creative possibilities + +If you specify the same image for clothing and avatar while providing a background prompt (or background image) you can +replace the background in a creative way: + +| Clothing Image | Avatar Image | Background Prompt | Result Image | +|----------------------------------------------------|----------------------------------------------------|-------------------------|-------------------------------------------------------------| +| | | on a snowy mountain top | | + +It's also possible to use a combination of clothing image, clothing prompt, avatar image and a background to add some +accessories: + +| Clothing Image | Clothing Prompt | Avatar Image | Background Image | Result Image | +|------------------------------------------------------|--------------------------|------------------------------------------------------|--------------------------------------------------------|------------------------------------------------------------------| +| | a (light brown purse)+++ | | | | + +## Performance + +Typically, one try-on request is processed in 5-10 seconds (depending on type of conditions) excluding network latency. +In order to reduce network overhead you might want to compress your images before feeding to the API (e.g. using JPEG). +Please note that in case of a high demand processing time might increase due to request being queued, though we +constantly monitor our GPU cluster capacity and perform scaling as needed. + +## Known Issues and Limitations + +As any generative model, our models are not perfect (though we constantly work on improvements): +- Currently, we do not fully support flat lay clothing images. Some might work, but that's not guaranteed. +- Prompt following might not be perfect, especially in case of long and sophisticated prompts. Prefer simpler and more + straightforward prompts whenever possible. Also be pretty verbose (e.g. use the word "plain" if you need something of + solid color). Additionally, Compel weighting might be used to increase weight of certain tokens. +- As usual, generative models struggle with hands, fingers and toes, though we try to mitigate it to a certain extent. +- Currently, we do not support trying on a single garment, only the full look. +- Hats and sunglasses are not currently transferred, but we are working on it. +- Backgrounds might lack some clarity as currently we focus more on clothing. +- In case of a specified background a hairstyle might change. +- Body shape of the avatar might change towards smaller sizes. diff --git a/docs/images/accessory_result_01.jpg b/docs/images/accessory_result_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a86d21bf60fdfa141543cf36f7d84695eac0e2b9 --- /dev/null +++ b/docs/images/accessory_result_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b1660d9df9205715cf017df5a6f520f0bb170ba20e34ac37f87eaeb6ad3f74b +size 193260 diff --git a/docs/images/avatar_image_01.jpg b/docs/images/avatar_image_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d282b0e4cc4f05cb0e08c1e1f734138c09df41af --- /dev/null +++ b/docs/images/avatar_image_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1291a821607d3630318961f184987c8a494bfcc70ac93a315d5aeb8842475b50 +size 425417 diff --git a/docs/images/avatar_image_02.jpg b/docs/images/avatar_image_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..15d65b5888dedb055c0913b0a49c36c62b8e369b --- /dev/null +++ b/docs/images/avatar_image_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a8f92656f1243d3d9562f91807fa8d3ca11bf66ad9dd3736630f88862d76110b +size 262033 diff --git a/docs/images/avatar_image_03.jpg b/docs/images/avatar_image_03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a8e431e9f60d77427742c19cda7aaf344001499b --- /dev/null +++ b/docs/images/avatar_image_03.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d9226c7ff9b67969cfa413c77c4c07974806009d59a96a15c4fbecdee1a5c8e2 +size 191058 diff --git a/docs/images/avatar_image_04.jpg b/docs/images/avatar_image_04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8a3a55490035847719a26286ec2498457c32a002 --- /dev/null +++ b/docs/images/avatar_image_04.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02831ba12b974525a94e439c353fd720a7dae14c102b4b11baf38c56822807f9 +size 352247 diff --git a/docs/images/avatar_modification_result_01.jpg b/docs/images/avatar_modification_result_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b3a44fea1002505ec7ac746a33b1a957ccdf4d2a --- /dev/null +++ b/docs/images/avatar_modification_result_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5c4d2adebeb2a27599b6a0ea532b8b25b5703697878c2bd4994466729c3e6f6b +size 190559 diff --git a/docs/images/avatar_modification_result_02.jpg b/docs/images/avatar_modification_result_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3900f45744c3bce84bc261508d89c1bc4231551 --- /dev/null +++ b/docs/images/avatar_modification_result_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7447675d79262d0120d6054c96e6723222c2d74451a4ba83a4b28e78fc900c76 +size 144339 diff --git a/docs/images/avatar_prompt_result_01.jpg b/docs/images/avatar_prompt_result_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..912f6dbe88904a6c4a044a6d0b8bcc389bf86a77 --- /dev/null +++ b/docs/images/avatar_prompt_result_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:06df6a8f830cff7c71459712c8c8bb4edb394580a818bd681644760f96c92dd9 +size 259852 diff --git a/docs/images/avatar_prompt_result_02.jpg b/docs/images/avatar_prompt_result_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..694d4af3325e19e5dd49a108768b557ba0847120 --- /dev/null +++ b/docs/images/avatar_prompt_result_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b20354374b2366729696d55ede627dc5fbb0cab22d374d4f4200b7283eb60417 +size 159959 diff --git a/docs/images/avatar_prompt_result_03.jpg b/docs/images/avatar_prompt_result_03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f9f1dfe73b3c3117dc8046272eec9168d4726bda --- /dev/null +++ b/docs/images/avatar_prompt_result_03.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a40abc74cd27451b6b439a91b8c26e3e2318cd5202b2f0113faecc36a2c44f49 +size 116472 diff --git a/docs/images/background_image_01.jpg b/docs/images/background_image_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..55c8064ce872fd12c2b3dc640de84fe8f2a48398 --- /dev/null +++ b/docs/images/background_image_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc6ad7187561a6a29044accc996aa242c48ea92f707d245dfdd75d545affd0bf +size 492498 diff --git a/docs/images/background_image_02.jpg b/docs/images/background_image_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2b8637e4c4c4c540ea0b0719a1507d321a463603 --- /dev/null +++ b/docs/images/background_image_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a92ab3827aecf1c683f2a5c3f44ae546ede0769e74bbae238ca0380a50fcc6b +size 700410 diff --git a/docs/images/background_image_03.jpg b/docs/images/background_image_03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cc8ece526517cb63d05d8a10b7e89d433a87b3ef --- /dev/null +++ b/docs/images/background_image_03.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:661a22b8d8442ad42d6dfa3e0ff563ed421ee7afab07d9bcf4ff5359f41c9d5f +size 511204 diff --git a/docs/images/background_image_04.jpg b/docs/images/background_image_04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a1ae17609093f2bfc0e98cb87111f9af204d6e63 --- /dev/null +++ b/docs/images/background_image_04.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e865e32c08a6f98fb92e9da07d646f927f08aa577b8fa30283ec7624474d5286 +size 357103 diff --git a/docs/images/clothing_image_01.jpg b/docs/images/clothing_image_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ab15ecb0ff9ea879ae53c02321e884542a39eaee --- /dev/null +++ b/docs/images/clothing_image_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:185a51562b6b04b8bc52eaf56c21451325af4379f6cfde4a7dcca8a15f1575c3 +size 398418 diff --git a/docs/images/clothing_image_02.jpg b/docs/images/clothing_image_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9eb29e170ce11e271aa35addaeb5a920760fb0e1 --- /dev/null +++ b/docs/images/clothing_image_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:533de7bd0e3ae1862304523e2035d8ba0015109e8a39368a017a9a757144bafa +size 433637 diff --git a/docs/images/clothing_image_03.jpg b/docs/images/clothing_image_03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3911e16515cdf4dca7b78d3133bca233bc1e090 --- /dev/null +++ b/docs/images/clothing_image_03.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9495af8b97285a3456bfbb684881cd8c1ba9bfd76e215843d24caeb22c64c9f8 +size 312679 diff --git a/docs/images/clothing_image_04.jpg b/docs/images/clothing_image_04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8efa0293365fe686018dfeac0002634f19aa064c --- /dev/null +++ b/docs/images/clothing_image_04.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfee3b092114533daf468a03707da516433acfc2076ced135e604ba4a7904512 +size 407478 diff --git a/docs/images/clothing_prompt_result_01.jpg b/docs/images/clothing_prompt_result_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..13901a8e1142750ac45d342580229b1de740ca35 --- /dev/null +++ b/docs/images/clothing_prompt_result_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3143f5aedd059a43325c6e5f99a408f04966beea840f64c2170839de97ada65c +size 119574 diff --git a/docs/images/clothing_prompt_result_02.jpg b/docs/images/clothing_prompt_result_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..77c795ef98f81afd1ca3fc452da485dcf8dedee9 --- /dev/null +++ b/docs/images/clothing_prompt_result_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5c5400a8899eccfd85a8550f1240aae2a6a3b838894e1afa72535a18cf9100a5 +size 178013 diff --git a/docs/images/image_based_background_result_01.jpg b/docs/images/image_based_background_result_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..18f9f1adc433ae35a8c19ff28348750e9d127cff --- /dev/null +++ b/docs/images/image_based_background_result_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:359ba35386a578aea598df4044020e5ce5f1b5ce323f98e024c906d23d1a671b +size 216101 diff --git a/docs/images/image_based_background_result_02.jpg b/docs/images/image_based_background_result_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d636db243949b661191d28f86d84044d370c5143 --- /dev/null +++ b/docs/images/image_based_background_result_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7fb59f6770466a27bccc396cd7040b5bce90cd8c9b3d8daf7466ab95c53272a4 +size 281709 diff --git a/docs/images/image_based_result_01.jpg b/docs/images/image_based_result_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7f307f5bf802f0993286be7e4de7b32a7b13ad5c --- /dev/null +++ b/docs/images/image_based_result_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b907d7e15cbd2a6bc822acd3bb580421cacf6f057c28c4d891d5db9f3365b4fb +size 147576 diff --git a/docs/images/new_background_result_01.jpg b/docs/images/new_background_result_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ca0eee663bdaee335233bc03c9e80c41415740fc --- /dev/null +++ b/docs/images/new_background_result_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:643f043d2c9fd5553851021d55aef549d610cba36ac2169ae1173d55278b22b5 +size 239774 diff --git a/docs/images/same_crop_result_01.jpg b/docs/images/same_crop_result_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8d6b614ac596c7564ffff6fddf061d2150070936 --- /dev/null +++ b/docs/images/same_crop_result_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:014b109c9fd456dd2389031283ba5ce7ddf7a674f0eca47ade4c9044de907f84 +size 189648 diff --git a/docs/images/same_crop_result_02.jpg b/docs/images/same_crop_result_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25c9bf8cabb5aee8db404bbf6d7f3e4c80966160 --- /dev/null +++ b/docs/images/same_crop_result_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5e48023a99d70ecc69975e5618a3789b6503d40d856a5767e3a2d564acad224c +size 159149 diff --git a/docs/images/txt2img_result_01.jpg b/docs/images/txt2img_result_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..12c1df5865b06c931bf214d630c2b80f23230745 --- /dev/null +++ b/docs/images/txt2img_result_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68fddf34ccabc2ce5580af2d3bb1415ab20971711d64d4cd078a74c5513e9cec +size 185590 diff --git a/docs/images/txt2img_result_02.jpg b/docs/images/txt2img_result_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..efc31ee61257e68ca970a0650f515d5020ca2f32 --- /dev/null +++ b/docs/images/txt2img_result_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a818bab8929bca1c23d16b0bd9c440d9a2247bff4c69e839f9594d838d1fc9a1 +size 171412 diff --git a/examples/avatar/female_01.jpg b/examples/avatar/female_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1bc94966ea2ff3072760c907007ebbc0e6200a09 --- /dev/null +++ b/examples/avatar/female_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:feb60696275f5276bcc0dc65e14bd972440b7973baa41609d0b6334d8b1c9880 +size 210621 diff --git a/examples/avatar/female_02.jpg b/examples/avatar/female_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d214724450f5e8cfaec54dc3af6d0f0d60741201 --- /dev/null +++ b/examples/avatar/female_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b02efe2043a9af0fa79bdc892b2e8535cc9fe83e3887e6ae49f14bff2f6faa0 +size 293740 diff --git a/examples/avatar/female_03.jpg b/examples/avatar/female_03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9552dd27589669185df178b069e75441176b0dd5 --- /dev/null +++ b/examples/avatar/female_03.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:70653888c42588a919f5eec01f7ce861cb19dd906f97f0c446d266d4c791b51b +size 194511 diff --git a/examples/avatar/female_04.jpg b/examples/avatar/female_04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9b2e41917f5e2039439aac4e1103169cb736c5ba --- /dev/null +++ b/examples/avatar/female_04.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4711e7d8e08cda7b29f331c1a790c729bbe264587c59dd76b6370c9e6491845c +size 415816 diff --git a/examples/avatar/female_05.jpg b/examples/avatar/female_05.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d282b0e4cc4f05cb0e08c1e1f734138c09df41af --- /dev/null +++ b/examples/avatar/female_05.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1291a821607d3630318961f184987c8a494bfcc70ac93a315d5aeb8842475b50 +size 425417 diff --git a/examples/avatar/female_06.jpg b/examples/avatar/female_06.jpg new file mode 100644 index 0000000000000000000000000000000000000000..15d65b5888dedb055c0913b0a49c36c62b8e369b --- /dev/null +++ b/examples/avatar/female_06.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a8f92656f1243d3d9562f91807fa8d3ca11bf66ad9dd3736630f88862d76110b +size 262033 diff --git a/examples/avatar/male_01.jpg b/examples/avatar/male_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a8e431e9f60d77427742c19cda7aaf344001499b --- /dev/null +++ b/examples/avatar/male_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d9226c7ff9b67969cfa413c77c4c07974806009d59a96a15c4fbecdee1a5c8e2 +size 191058 diff --git a/examples/avatar/male_02.jpg b/examples/avatar/male_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8a3a55490035847719a26286ec2498457c32a002 --- /dev/null +++ b/examples/avatar/male_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02831ba12b974525a94e439c353fd720a7dae14c102b4b11baf38c56822807f9 +size 352247 diff --git a/examples/avatar/male_03.jpg b/examples/avatar/male_03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..72b0234ea12868df21d3c050dc2a0e54507eee4b --- /dev/null +++ b/examples/avatar/male_03.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d9441acd683a497d4108582abb99bc333643de3368c05fffb9e911c7d3d1106 +size 123137 diff --git a/examples/avatar/male_04.jpg b/examples/avatar/male_04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..364091615af119d602058dc30f2927655e1fa05d --- /dev/null +++ b/examples/avatar/male_04.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:99ecc2bf9d21bdd22d1c42bfeab8537ee3dd1ce7139c3d15c6be9e782040a0fb +size 361348 diff --git a/examples/avatar/male_05.jpg b/examples/avatar/male_05.jpg new file mode 100644 index 0000000000000000000000000000000000000000..725618906543e19a2fb38ed6847e8cba5ce01cde --- /dev/null +++ b/examples/avatar/male_05.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf364572f22b23c3567dc8f169e329a20f3e3def7cf1bc2e4349d98f16351d87 +size 170148 diff --git a/examples/avatar/male_06.jpg b/examples/avatar/male_06.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c4127928e17a658995df55625cd5494d95c06b19 --- /dev/null +++ b/examples/avatar/male_06.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bba21beb25ff292a6917e9cd377ccd53a63b46c97a4bb1e87d8c324a0187a52a +size 308308 diff --git a/examples/background/01.jpg b/examples/background/01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..55c8064ce872fd12c2b3dc640de84fe8f2a48398 --- /dev/null +++ b/examples/background/01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc6ad7187561a6a29044accc996aa242c48ea92f707d245dfdd75d545affd0bf +size 492498 diff --git a/examples/background/02.jpg b/examples/background/02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2b8637e4c4c4c540ea0b0719a1507d321a463603 --- /dev/null +++ b/examples/background/02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a92ab3827aecf1c683f2a5c3f44ae546ede0769e74bbae238ca0380a50fcc6b +size 700410 diff --git a/examples/background/03.jpg b/examples/background/03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..60ee5e8cb515f87eb31b74a444d5ab5145cfdb11 --- /dev/null +++ b/examples/background/03.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0f7f1044891103c2e5697c3b7cbd36ca869c63982f11a266077601b51549b74c +size 336069 diff --git a/examples/background/04.jpg b/examples/background/04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cc8ece526517cb63d05d8a10b7e89d433a87b3ef --- /dev/null +++ b/examples/background/04.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:661a22b8d8442ad42d6dfa3e0ff563ed421ee7afab07d9bcf4ff5359f41c9d5f +size 511204 diff --git a/examples/background/05.jpg b/examples/background/05.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1bc8bcb42db3106a13b36bbacd06e69fdd85ee0f --- /dev/null +++ b/examples/background/05.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e311072b112866f7201474d83ba49eaa0fa695f2e589e83fd922d05e0c28195d +size 391616 diff --git a/examples/background/06.jpg b/examples/background/06.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5c55d8bd9d3396e49a5de8bc04cc5555c7ef6331 --- /dev/null +++ b/examples/background/06.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7b35a710cfba95a2816aacac8dc9d1bec3ff52ced993417c418d6d0c0ac562a +size 388663 diff --git a/examples/background/07.jpg b/examples/background/07.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5a680854fcc46bcdb06708c89c2582a8ba6b568f --- /dev/null +++ b/examples/background/07.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:90f336f9b994a9f641d833d2f7e9f73002b0bfb08f2744171741fb862c5ffa24 +size 552901 diff --git a/examples/background/08.jpg b/examples/background/08.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a6f8d5b0dda5ad5588abc82342d87c6c8019663b --- /dev/null +++ b/examples/background/08.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ef2954e7043187da9f54d1674cf4a31199edb258a19f12001b6e18c15bde7d57 +size 384461 diff --git a/examples/background/09.jpg b/examples/background/09.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5df950c833ffe9e4b4bb1cc29801c83402522e9d --- /dev/null +++ b/examples/background/09.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c23c1e456b78be12fca054820222678905d9e775a8f9d3c95bcf885248deb90 +size 438174 diff --git a/examples/background/10.jpg b/examples/background/10.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1b7f12e400d325f1e57d13ae724f6cf149089c7e --- /dev/null +++ b/examples/background/10.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a8a1342c72651307168618178dac0db65550af33e73a10e64e3d24428988434 +size 315379 diff --git a/examples/background/11.jpg b/examples/background/11.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a1ae17609093f2bfc0e98cb87111f9af204d6e63 --- /dev/null +++ b/examples/background/11.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e865e32c08a6f98fb92e9da07d646f927f08aa577b8fa30283ec7624474d5286 +size 357103 diff --git a/examples/background/12.jpg b/examples/background/12.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cc05eaf7dfd5727e94dc66ac7e4b0aeb9ed6a5d5 --- /dev/null +++ b/examples/background/12.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4aa0f4dc7d148d55082c34534c382642e67b454c199befb7531c8b2b05145cd1 +size 407209 diff --git a/examples/clothing/female_01.jpg b/examples/clothing/female_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ab15ecb0ff9ea879ae53c02321e884542a39eaee --- /dev/null +++ b/examples/clothing/female_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:185a51562b6b04b8bc52eaf56c21451325af4379f6cfde4a7dcca8a15f1575c3 +size 398418 diff --git a/examples/clothing/female_02.jpg b/examples/clothing/female_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9eb29e170ce11e271aa35addaeb5a920760fb0e1 --- /dev/null +++ b/examples/clothing/female_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:533de7bd0e3ae1862304523e2035d8ba0015109e8a39368a017a9a757144bafa +size 433637 diff --git a/examples/clothing/female_03.jpg b/examples/clothing/female_03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ca1d00ed3c87a88a854245bff908fbd16a0116b4 --- /dev/null +++ b/examples/clothing/female_03.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d2531c286cfd8a25214691a4ed3f78bf6f9a3ea9d95a026784fe1b61482310ea +size 306223 diff --git a/examples/clothing/female_04.jpg b/examples/clothing/female_04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f09b627fe46407d1ad9359c7e646324c837f979a --- /dev/null +++ b/examples/clothing/female_04.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37a9c7f329ea51deaf80fd7592484ea065fbe7e0486aa2913fc0a85e48383004 +size 277926 diff --git a/examples/clothing/female_05.jpg b/examples/clothing/female_05.jpg new file mode 100644 index 0000000000000000000000000000000000000000..41a5efb2c0f6998282bf9143342a5d809440f537 --- /dev/null +++ b/examples/clothing/female_05.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dac6b6ca50e3a81fe1c01f6a5975f894cdd2c5553705325d5d8dfa66447f41f4 +size 245201 diff --git a/examples/clothing/female_06.jpg b/examples/clothing/female_06.jpg new file mode 100644 index 0000000000000000000000000000000000000000..37eb64ec95aa55f35d6fcdd73b2b7831012667c0 --- /dev/null +++ b/examples/clothing/female_06.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:790d96ee414267ccd3255b9aae12aa4946a5f452eace0413ca0bea508694c03f +size 445195 diff --git a/examples/clothing/male_01.jpg b/examples/clothing/male_01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3679d513a816265e4128425637ba9276fadea5ad --- /dev/null +++ b/examples/clothing/male_01.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3152b0a7e9b869f19aae0deb156359ffc87ce7efbf3a7a8cc35722b38c93853b +size 444456 diff --git a/examples/clothing/male_02.jpg b/examples/clothing/male_02.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3911e16515cdf4dca7b78d3133bca233bc1e090 --- /dev/null +++ b/examples/clothing/male_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9495af8b97285a3456bfbb684881cd8c1ba9bfd76e215843d24caeb22c64c9f8 +size 312679 diff --git a/examples/clothing/male_03.jpg b/examples/clothing/male_03.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8efa0293365fe686018dfeac0002634f19aa064c --- /dev/null +++ b/examples/clothing/male_03.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfee3b092114533daf468a03707da516433acfc2076ced135e604ba4a7904512 +size 407478 diff --git a/examples/clothing/male_04.jpg b/examples/clothing/male_04.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4602e11f3433a2e6b93cffeb07abfe2ed89803d1 --- /dev/null +++ b/examples/clothing/male_04.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:237d41460b8e53c4aa1f0f6c41ff99247215edb762c25f0ffd8a0b59842063a5 +size 447192 diff --git a/examples/clothing/male_05.jpg b/examples/clothing/male_05.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9f1aa8cf5e0a8a47a24238a32ced3da245f71398 --- /dev/null +++ b/examples/clothing/male_05.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:42da86578bacd3b16e4ad764a641a4f79034cb23227151fa3285d95c33083c3c +size 525021 diff --git a/examples/clothing/male_06.jpg b/examples/clothing/male_06.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7605a6d548c76bda11f4ea7e03443a0601274a4b --- /dev/null +++ b/examples/clothing/male_06.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7af38fbc2886c265fb534a9684f60aad842cf83ee99696a56094c66267080df +size 398874 diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..542bc4cea11fbce2df86d8b93b3a27be13538076 --- /dev/null +++ b/images/logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ef4aeca425cb5a3fe10ac0e291cd0512200822ca5a52bf41e8c086b6bdfb19b +size 20349 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c8d743410d850c687b1fe8cbf548c147f6c64f9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +requests==2.32.3 +requests_toolbelt==1.0.0 +numpy==1.26.4 +opencv-python-headless==4.10.0.84 diff --git a/try_on_diffusion_client.py b/try_on_diffusion_client.py new file mode 100644 index 0000000000000000000000000000000000000000..7c12de005cd76eafd244493a0135a3613c39ea0f --- /dev/null +++ b/try_on_diffusion_client.py @@ -0,0 +1,130 @@ +import cv2 +import numpy as np +import requests +from requests_toolbelt.multipart.encoder import MultipartEncoder +from urllib.parse import urlparse +import logging +import json +from io import BytesIO +from dataclasses import dataclass + + +@dataclass +class TryOnDiffusionAPIResponse: + status_code: int + image: np.ndarray = None + response_data: bytes = None + error_details: str = None + seed: int = None + + +class TryOnDiffusionClient: + def __init__(self, base_url: str = "http://localhost:8000/", api_key: str = ""): + self._logger = logging.getLogger("try_on_diffusion_client") + self._base_url = base_url + self._api_key = api_key + + if self._base_url[-1] == "/": + self._base_url = self._base_url[:-1] + + parsed_url = urlparse(self._base_url) + + self._rapidapi_host = parsed_url.netloc if parsed_url.netloc.endswith(".rapidapi.com") else None + + if self._rapidapi_host is not None: + self._logger.info(f"Using RapidAPI proxy: {self._rapidapi_host}") + + @staticmethod + def _image_to_upload_file(image: np.ndarray) -> tuple: + _, jpeg_data = cv2.imencode(".jpg", image, [int(cv2.IMWRITE_JPEG_QUALITY), 99]) + jpeg_data = jpeg_data.tobytes() + + fp = BytesIO(jpeg_data) + + return "image.jpg", fp, "image/jpeg" + + def try_on_file( + self, + clothing_image: np.ndarray = None, + clothing_prompt: str = None, + avatar_image: np.ndarray = None, + avatar_prompt: str = None, + avatar_sex: str = None, + background_image: np.ndarray = None, + background_prompt: str = None, + seed: int = -1, + raw_response: bool = False, + ) -> TryOnDiffusionAPIResponse: + url = self._base_url + "/try-on-file" + + request_data = {"seed": str(seed)} + + if clothing_image is not None: + request_data["clothing_image"] = self._image_to_upload_file(clothing_image) + + if clothing_prompt is not None: + request_data["clothing_prompt"] = clothing_prompt + + if avatar_image is not None: + request_data["avatar_image"] = self._image_to_upload_file(avatar_image) + + if avatar_prompt is not None: + request_data["avatar_prompt"] = avatar_prompt + + if avatar_sex is not None: + request_data["avatar_sex"] = avatar_sex + + if background_image is not None: + request_data["background_image"] = self._image_to_upload_file(background_image) + + if background_prompt is not None: + request_data["background_prompt"] = background_prompt + + multipart_data = MultipartEncoder(fields=request_data) + + headers = {"Content-Type": multipart_data.content_type} + + if self._rapidapi_host is not None: + headers["X-RapidAPI-Key"] = self._api_key + headers["X-RapidAPI-Host"] = self._rapidapi_host + else: + headers["X-API-Key"] = self._api_key + + try: + response = requests.post( + url, + data=multipart_data, + headers=headers, + ) + except Exception as e: + self._logger.error(e, exc_info=True) + return TryOnDiffusionAPIResponse(status_code=0) + + if response.status_code != 200: + self._logger.warning(f"Request failed, status code: {response.status_code}, response: {response.content}") + + result = TryOnDiffusionAPIResponse(status_code=response.status_code) + + if not raw_response and response.status_code == 200: + try: + result.image = cv2.imdecode(np.frombuffer(response.content, np.uint8), cv2.IMREAD_COLOR) + except: + result.image = None + else: + result.response_data = response.content + + if result.status_code == 200: + if "X-Seed" in response.headers: + result.seed = int(response.headers["X-Seed"]) + else: + try: + response_json = ( + json.loads(result.response_data.decode("utf-8")) if result.response_data is not None else None + ) + + if response_json is not None and "detail" in response_json: + result.error_details = response_json["detail"] + except: + result.error_details = None + + return result