{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LxultT3VptKy"
      },
      "outputs": [],
      "source": [
        "# Copyright 2025 Google LLC\n",
        "#\n",
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "#     https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FROnodhKp4vU"
      },
      "source": [
        "# Virtual Try-On: Batch Generation Pipeline\n",
        "\n",
        "<table align=\"left\">\n",
        "  <td style=\"text-align: center\">\n",
        "    <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/vision/use-cases/batch_virtual_try_on.ipynb\">\n",
        "      <img src=\"https://www.gstatic.com/pantheon/images/bigquery/welcome_page/colab-logo.svg\" alt=\"Google Colaboratory logo\"><br> Run in Colab\n",
        "    </a>\n",
        "  </td>\n",
        "  <td style=\"text-align: center\">\n",
        "    <a href=\"https://console.cloud.google.com/vertex-ai/colab/import/https:%2F%2Fraw.githubusercontent.com%2FGoogleCloudPlatform%2Fgenerative-ai%2Fmain%2Fvision%2Fuse-cases%2Fbatch_virtual_try_on.ipynb\">\n",
        "      <img width=\"32px\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" alt=\"Google Cloud Colab Enterprise logo\"><br> Run in Colab Enterprise\n",
        "    </a>\n",
        "  </td>\n",
        "  <td style=\"text-align: center\">\n",
        "    <a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/generative-ai/main/vision/use-cases/batch_virtual_try_on.ipynb\">\n",
        "      <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\"><br> Open in Vertex AI Workbench\n",
        "    </a>\n",
        "  </td>    \n",
        "  <td style=\"text-align: center\">\n",
        "    <a href=\"https://github.com/GoogleCloudPlatform/generative-ai/blob/main/vision/use-cases/batch_virtual_try_on.ipynb\">\n",
        "      <img width=\"32px\" src=\"https://raw.githubusercontent.com/primer/octicons/refs/heads/main/icons/mark-github-24.svg\" alt=\"GitHub logo\"><br> View on GitHub\n",
        "    </a>\n",
        "  </td>\n",
        "</table>\n",
        "\n",
        "<div style=\"clear: both;\"></div>\n",
        "\n",
        "<b>Share to:</b>\n",
        "\n",
        "<a href=\"https://www.linkedin.com/sharing/share-offsite/?url=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/vision/use-cases/batch_virtual_try_on.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/8/81/LinkedIn_icon.svg\" alt=\"LinkedIn logo\">\n",
        "</a>\n",
        "\n",
        "<a href=\"https://bsky.app/intent/compose?text=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/vision/use-cases/batch_virtual_try_on.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/7/7a/Bluesky_Logo.svg\" alt=\"Bluesky logo\">\n",
        "</a>\n",
        "\n",
        "<a href=\"https://twitter.com/intent/tweet?url=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/vision/use-cases/batch_virtual_try_on.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/5/5a/X_icon_2.svg\" alt=\"X logo\">\n",
        "</a>\n",
        "\n",
        "<a href=\"https://reddit.com/submit?url=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/vision/use-cases/batch_virtual_try_on.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://redditinc.com/hubfs/Reddit%20Inc/Brand/Reddit_Logo.png\" alt=\"Reddit logo\">\n",
        "</a>\n",
        "\n",
        "<a href=\"https://www.facebook.com/sharer/sharer.php?u=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/vision/use-cases/batch_virtual_try_on.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/5/51/Facebook_f_logo_%282019%29.svg\" alt=\"Facebook logo\">\n",
        "</a>  "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kVzXSHsWzfcx"
      },
      "source": [
        "| Authors |\n",
        "| --- |\n",
        "| [Wafae Bakkali](https://github.com/WafaeBakkali) |\n",
        "| [Katie Nguyen](https://github.com/katiemn) |"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "exrbLwZCzwdm"
      },
      "source": [
        "## Overview\n",
        "\n",
        "### Virtual Try-On\n",
        "\n",
        "[Virtual Try-On](https://cloud.google.com/vertex-ai/generative-ai/docs/image/generate-virtual-try-on-images) uses Google's advanced image generation models to create high-quality images of people virtually trying on clothing. By providing an image of a human model and a clothing product, you can generate an image of the model wearing that product. This technology is designed for application developers and retailers in the fashion industry.\n",
        "\n",
        "This tutorial demonstrates how to use the Virtual Try-On API to automate batch processing, i.e., generating multiple results across various combinations of person and apparel images. In this tutorial, you will learn how to use the Google Gen AI SDK for Python to interact with the Virtual Try-On model to:\n",
        " - Upload images from local sources, Cloud Storage, or other URL-based inputs\n",
        " - Return side-by-side visual outputs to preview the try-on results"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nd86wufNz0Ze"
      },
      "source": [
        "## Get started"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qUAdq4Iz-hoy"
      },
      "source": [
        "### Install Google Gen AI SDK for Python"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ImzTDW9m-kuD"
      },
      "outputs": [],
      "source": [
        "%pip install --upgrade --quiet google-genai"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "caZ9JpIlh9V_"
      },
      "source": [
        "### Authenticate your notebook environment (Colab only)\n",
        "\n",
        "If you are running this notebook on Google Colab, run the following cell to authenticate your environment."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "XWCHsLNJREe2"
      },
      "outputs": [],
      "source": [
        "import sys\n",
        "\n",
        "if \"google.colab\" in sys.modules:\n",
        "    from google.colab import auth\n",
        "\n",
        "    auth.authenticate_user()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9OHJ7O1fALAB"
      },
      "source": [
        "### Import libraries"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "id": "wbj-UXJNAN4V"
      },
      "outputs": [],
      "source": [
        "import io\n",
        "import time\n",
        "import zipfile\n",
        "\n",
        "from PIL import Image as PIL_Image\n",
        "from google import genai\n",
        "from google.colab import files\n",
        "from google.genai.types import Image, ProductImage, RecontextImageSource\n",
        "import matplotlib.image as img\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "import requests"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Py2XWxe3RRud"
      },
      "source": [
        "### Set Google Cloud project information and create client\n",
        "\n",
        "To get started using Vertex AI, you must have an existing Google Cloud project and [enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com).\n",
        "\n",
        "Learn more about [setting up a project and a development environment](https://cloud.google.com/vertex-ai/docs/start/cloud-environment)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "id": "iEhbosxKRPcH"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "\n",
        "PROJECT_ID = \"[your-project-id]\"  # @param {type: \"string\", placeholder: \"[your-project-id]\", isTemplate: true}\n",
        "if not PROJECT_ID or PROJECT_ID == \"[your-project-id]\":\n",
        "    PROJECT_ID = str(os.environ.get(\"GOOGLE_CLOUD_PROJECT\"))\n",
        "\n",
        "LOCATION = os.environ.get(\"GOOGLE_CLOUD_REGION\", \"us-central1\")\n",
        "\n",
        "client = genai.Client(vertexai=True, project=PROJECT_ID, location=LOCATION)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rlHjmqj5A3k8"
      },
      "source": [
        "### Define helper functions"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "id": "3mrS8px7RdjF"
      },
      "outputs": [],
      "source": [
        "def display_images(images: list, type: str) -> None:\n",
        "    fig, axes = plt.subplots(1, len(images), figsize=(12, 6))\n",
        "    if len(images) == 1:\n",
        "        axes = np.array([axes])\n",
        "    for i, ax in enumerate(axes):\n",
        "        if type == \"local\":\n",
        "            image = img.imread(images[i])\n",
        "        elif type == \"url\":\n",
        "            response = requests.get(images[i])\n",
        "            image = PIL_Image.open(io.BytesIO(response.content))\n",
        "        # Display generated images\n",
        "        else:\n",
        "            image = images[i]._pil_image\n",
        "        ax.imshow(image)\n",
        "        ax.axis(\"off\")\n",
        "    plt.show()\n",
        "\n",
        "\n",
        "def process_urls(url_string):\n",
        "    urls = [url.strip() for url in url_string.split(\"\\n\") if url.strip()]\n",
        "    return urls\n",
        "\n",
        "\n",
        "def download_results_as_zip(results):\n",
        "    zip_filename = f\"virtual-try-on-results-{int(time.time())}.zip\"\n",
        "    with zipfile.ZipFile(zip_filename, \"w\", zipfile.ZIP_DEFLATED) as zip_file:\n",
        "        for i, result in enumerate(results):\n",
        "            image_data = result.image_bytes\n",
        "            zip_file.writestr(f\"result_{i+1}.png\", image_data)\n",
        "    files.download(zip_filename)\n",
        "    print(f\"Download started for {zip_filename}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RLLQstUOCFV1"
      },
      "source": [
        "### Load the image model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "id": "GDp_NibQCbny"
      },
      "outputs": [],
      "source": [
        "virtual_try_on = \"virtual-try-on-preview-08-04\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0eFV5m5MC-XK"
      },
      "source": [
        "## Batch processing with Virtual Try-On"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "OmhdutmeRkeG"
      },
      "source": [
        "### Upload person and apparel images\n",
        "\n",
        "In this tutorial you can select your images from your local computer or public URLs. Choose only one option per batch processing job.\n",
        "\n",
        "Supported Clothing:\n",
        "  - **Tops:** shirts, hoodies, sweaters, tank tops, blouses\n",
        "  - **Bottoms:** pants, leggings, shorts, skirts\n",
        "  - **Footwear:** sneakers, boots, sandals, flats, heels, formal shoes"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "giwjbVX1r2ac"
      },
      "source": [
        "#### **Option 1:** Use local images\n",
        "\n",
        "In this section, you'll upload images of people and clothing items to try them on from local files. Simply run the cell and select the images you'd like to use."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uO9FXGEFTzIk"
      },
      "outputs": [],
      "source": [
        "print(\"Please upload one or more PERSON images:\")\n",
        "person_files = files.upload()\n",
        "person_images = [img_name for img_name, img_bytes in person_files.items()]\n",
        "display_images(person_images, \"local\")\n",
        "\n",
        "print(\"\\nPlease upload one or more PRODUCT images:\")\n",
        "product_files = files.upload()\n",
        "product_images = [img_name for img_name, img_bytes in product_files.items()]\n",
        "display_images(product_images, \"local\")\n",
        "\n",
        "local_images = True"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NKHro9JSFEdP"
      },
      "source": [
        "#### **Option 2:** Use public images\n",
        "\n",
        "If you uploaded images through Option 1, skip this section. Otherwise, paste each URL on a new line in the appropriate variable below. Do not use comma-separated values or local file paths."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "t75hoe-8ov7d"
      },
      "outputs": [],
      "source": [
        "# Paste person URLs here, one per line\n",
        "person_urls = \"\"\"\n",
        "https://storage.googleapis.com/cloud-samples-data/generative-ai/image/man-in-field.png\n",
        "https://storage.googleapis.com/cloud-samples-data/generative-ai/image/woman.jpg\n",
        "\"\"\"\n",
        "\n",
        "# Paste product URLs here, one per line\n",
        "product_urls = \"\"\"\n",
        "https://storage.googleapis.com/cloud-samples-data/generative-ai/image/sweater.jpg\n",
        "https://storage.googleapis.com/cloud-samples-data/generative-ai/image/trousers.jpg\n",
        "\"\"\"\n",
        "\n",
        "person_images = process_urls(person_urls)\n",
        "product_images = process_urls(product_urls)\n",
        "\n",
        "display_images(person_images, \"url\")\n",
        "display_images(product_images, \"url\")\n",
        "\n",
        "local_images = False"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WJGO9d7KSBQ0"
      },
      "source": [
        "### Generate and view results\n",
        "\n",
        "Running the cell below will generate an image for each combination of model and clothing item. The results will be displayed below."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "EYcWev3ASCjL"
      },
      "outputs": [],
      "source": [
        "generated_results = []\n",
        "total_jobs = len(person_images) * len(product_images)\n",
        "current_job = 0\n",
        "\n",
        "for person_img in person_images:\n",
        "    for product_img in product_images:\n",
        "        current_job += 1\n",
        "        print(f\"Running job {current_job}/{total_jobs}...\")\n",
        "        try:\n",
        "            if local_images:\n",
        "                person_image_obj = Image.from_file(location=person_img)\n",
        "                product_image_obj = Image.from_file(location=product_img)\n",
        "            else:\n",
        "                person_response = requests.get(person_img)\n",
        "                person_response.raise_for_status()\n",
        "                person_image_obj = Image(image_bytes=person_response.content)\n",
        "\n",
        "                product_response = requests.get(product_img)\n",
        "                product_response.raise_for_status()\n",
        "                product_image_obj = Image(image_bytes=product_response.content)\n",
        "\n",
        "            generated_image = client.models.recontext_image(\n",
        "                model=virtual_try_on,\n",
        "                source=RecontextImageSource(\n",
        "                    person_image=person_image_obj,\n",
        "                    product_images=[ProductImage(product_image=product_image_obj)],\n",
        "                ),\n",
        "            )\n",
        "            generated_results.append(generated_image.generated_images[0].image)\n",
        "        except Exception as e:\n",
        "            print(f\"Skipping job {current_job}/{total_jobs} due to an error: {e}\")\n",
        "\n",
        "        time.sleep(2)  # Add a delay to help with API quota limits\n",
        "\n",
        "# Display results\n",
        "if generated_results:\n",
        "    display_images(generated_results, \"generated\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GpZmv8zbSYyy"
      },
      "source": [
        "### Download results locally in a ZIP file"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "FHHI5vsTShsd"
      },
      "outputs": [],
      "source": [
        "if generated_results:\n",
        "    download_results_as_zip(generated_results)"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "name": "batch_virtual_try_on.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
