{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uxCkB_DXTHzf"
      },
      "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": "Hny4I-ODTIS6"
      },
      "source": [
        "# Virtual Try-On: Image Generation\n",
        "\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/getting-started/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%2Fgetting-started%2Fvirtual_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/getting-started/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/getting-started/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/getting-started/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/getting-started/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/getting-started/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/getting-started/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/getting-started/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": "EXljS1-Ib0ue"
      },
      "source": [
        "| Authors |\n",
        "| --- |\n",
        "| [Jorj Ismailyan](https://github.com/jismailyan-google) |\n",
        "| [Katie Nguyen](https://github.com/katiemn) |"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-nLS57E2TO5y"
      },
      "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 cutting-edge image generation models to create high-quality images of people virtually trying on clothes. By providing an image of a model and a clothing item, you can generate a new image of the model wearing that product.\n",
        "\n",
        "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",
        "- Try-on multiple clothing items from locally stored images\n",
        "- Try-on a clothing item in Cloud Storage with an Imagen generated person\n",
        "\n",
        "Learn more about [quotas](https://cloud.google.com/vertex-ai/generative-ai/docs/models/imagen/virtual-try-on-preview-08-04) and [pricing](https://cloud.google.com/vertex-ai/generative-ai/pricing#imagen-models) for Virtual Try-On in the product documentation."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mvKl-BtQTRiQ"
      },
      "source": [
        "## Get started"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "B-UOCMvJdmlq"
      },
      "source": [
        "### Install Google Gen AI SDK for Python"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "u5lOntr-doIT"
      },
      "outputs": [],
      "source": [
        "%pip install --upgrade --quiet google-genai"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "opUxT_k5TdgP"
      },
      "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": null,
      "metadata": {
        "id": "vbNgv4q1T2Mi"
      },
      "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": "Sh5eUOaLsJ46"
      },
      "source": [
        "### Import libraries"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "id": "di-H-mflsM0E"
      },
      "outputs": [],
      "source": [
        "import typing\n",
        "import urllib.request\n",
        "\n",
        "import IPython.display\n",
        "from PIL import Image as PIL_Image\n",
        "from PIL import ImageOps as PIL_ImageOps\n",
        "from google import genai\n",
        "from google.genai.types import (\n",
        "    GenerateImagesConfig,\n",
        "    Image,\n",
        "    ProductImage,\n",
        "    RecontextImageConfig,\n",
        "    RecontextImageSource,\n",
        ")\n",
        "import matplotlib.image as img\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ybBXSukZkgjg"
      },
      "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": "q7YvbXXdtzDT"
      },
      "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": "ic4fVqs8skdA"
      },
      "source": [
        "### Define helper functions to display media"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "id": "hk8bfm7Xsvg8"
      },
      "outputs": [],
      "source": [
        "def display_image(\n",
        "    image,\n",
        "    max_width: int = 700,\n",
        "    max_height: int = 400,\n",
        ") -> None:\n",
        "    pil_image = typing.cast(PIL_Image.Image, image._pil_image)\n",
        "    if pil_image.mode != \"RGB\":\n",
        "        # RGB is supported by all Jupyter environments (e.g. RGBA is not yet)\n",
        "        pil_image = pil_image.convert(\"RGB\")\n",
        "    image_width, image_height = pil_image.size\n",
        "    if max_width < image_width or max_height < image_height:\n",
        "        # Resize to display a smaller notebook image\n",
        "        pil_image = PIL_ImageOps.contain(pil_image, (max_width, max_height))\n",
        "    IPython.display.display(pil_image)\n",
        "\n",
        "\n",
        "def display_local_image(\n",
        "    images: list[str],\n",
        ") -> 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",
        "        image = img.imread(images[i])\n",
        "        ax.imshow(image)\n",
        "        ax.axis(\"off\")\n",
        "    plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qnEcP0UUsy-_"
      },
      "source": [
        "### Load the image models"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "id": "w_TfEzggs2fp"
      },
      "outputs": [],
      "source": [
        "virtual_try_on = \"virtual-try-on-preview-08-04\"\n",
        "image_generation = \"imagen-4.0-generate-001\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fU32286ooc8Q"
      },
      "source": [
        "## Virtual Try-On with local files\n",
        "\n",
        "In this section, you'll download images of a person and clothing items to try them on from local files.\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\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "faTZezkUs7KP"
      },
      "source": [
        "### Download an image of a person\n",
        "\n",
        "First, download an image of a person. The following example uses an image from Cloud Storage. If you prefer to use a different image, you can either change the URL in the `wget` command or, if you have a local file, update the `person_image` variable in the subsequent step."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "19kR3OR7Fwgv"
      },
      "outputs": [],
      "source": [
        "!wget https://storage.googleapis.com/cloud-samples-data/generative-ai/image/man-in-field.png"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "p04U4s73tRe2"
      },
      "source": [
        "If you'd like to use a different local image, modify the file name in `person_image`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Spzul-ObF00N"
      },
      "outputs": [],
      "source": [
        "person_image = \"man-in-field.png\"  # @param {type: 'string'}\n",
        "\n",
        "display_local_image([person_image])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SRgtZr0YteN2"
      },
      "source": [
        "### Download clothing images\n",
        "\n",
        "Next, download the clothing images. The examples below are stored in Cloud Storage, but you can use your own by modifying the URLs or by specifying the paths to local images in the next step."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "b5HxMgDpMQta"
      },
      "outputs": [],
      "source": [
        "!wget https://storage.googleapis.com/cloud-samples-data/generative-ai/image/sweater.jpg\n",
        "\n",
        "!wget https://storage.googleapis.com/cloud-samples-data/generative-ai/image/trousers.jpg"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mm-jYPq5t7yN"
      },
      "source": [
        "If you'd like to use a different top, modify the file name in `top_image`. The same goes for the file name in `bottom_image`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "IY0LHYHfMjkK"
      },
      "outputs": [],
      "source": [
        "top_image = \"sweater.jpg\"  # @param {type: 'string'}\n",
        "bottom_image = \"trousers.jpg\"  # @param {type: 'string'}\n",
        "\n",
        "display_local_image([top_image, bottom_image])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mTgQo5Hauk92"
      },
      "source": [
        "### Send the request\n",
        "\n",
        "With the Virtual Try-On model, you can only specify one clothing item to try on at a time. Since this example has two clothing items, you'll need to make two separate requests. In each call, you can specify the following parameters in addition to the `person_image` and `product_images`:\n",
        " - **Number of images:** 1 - 4\n",
        "\n",
        "You'll save the output image locally so that it can be referenced in the next step."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RHnSHJl-t8ud"
      },
      "outputs": [],
      "source": [
        "response = client.models.recontext_image(\n",
        "    model=virtual_try_on,\n",
        "    source=RecontextImageSource(\n",
        "        person_image=Image.from_file(location=person_image),\n",
        "        product_images=[\n",
        "            ProductImage(product_image=Image.from_file(location=top_image))\n",
        "        ],\n",
        "    ),\n",
        "    config=RecontextImageConfig(\n",
        "        output_mime_type=\"image/jpeg\",\n",
        "        number_of_images=1,\n",
        "        safety_filter_level=\"BLOCK_LOW_AND_ABOVE\",\n",
        "    ),\n",
        ")\n",
        "\n",
        "response.generated_images[0].image.save(\"try-on.jpeg\")\n",
        "display_image(response.generated_images[0].image)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cP_gkDUVx-3Z"
      },
      "source": [
        "When generating images you can also set the `safety_filter_level` parameter accordingly:\n",
        "- `safety_filter_level`\n",
        "  - `BLOCK_LOW_AND_ABOVE`\n",
        "  - `BLOCK_MEDIUM_AND_ABOVE`\n",
        "  - `BLOCK_ONLY_HIGH`\n",
        "  - `BLOCK_NONE`"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JKtLpyrZ3wA5"
      },
      "outputs": [],
      "source": [
        "response = client.models.recontext_image(\n",
        "    model=virtual_try_on,\n",
        "    source=RecontextImageSource(\n",
        "        person_image=Image.from_file(location=\"try-on.jpeg\"),\n",
        "        product_images=[\n",
        "            ProductImage(product_image=Image.from_file(location=bottom_image))\n",
        "        ],\n",
        "    ),\n",
        "    config=RecontextImageConfig(\n",
        "        output_mime_type=\"image/jpeg\",\n",
        "        number_of_images=1,\n",
        "        safety_filter_level=\"BLOCK_LOW_AND_ABOVE\",\n",
        "    ),\n",
        ")\n",
        "display_image(response.generated_images[0].image)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mBLJtICO8iMQ"
      },
      "source": [
        "## Virtual Try-On with files in Cloud Storage\n",
        "\n",
        "In this section, you'll use images of a clothing item stored in Cloud Storage and a person generated with Imagen for virtual try-on."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "08ZEbEDgyyCB"
      },
      "source": [
        "### Generate an image of a person\n",
        "\n",
        "In this example, you'll generate a person to try on the clothing item with Imagen. Run the step below and change the prompt if you see fit."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "I9caIrZ7Dek1"
      },
      "outputs": [],
      "source": [
        "prompt = \"\"\"\n",
        "A high-resolution, full-body, head-on photograph of a woman standing in a brightly lit professional photography studio wearing a dress. The backdrop is clean gray paper.\n",
        "\"\"\"\n",
        "\n",
        "image = client.models.generate_images(\n",
        "    model=image_generation,\n",
        "    prompt=prompt,\n",
        "    config=GenerateImagesConfig(\n",
        "        output_mime_type=\"image/jpeg\",\n",
        "        number_of_images=1,\n",
        "        image_size=\"2K\",\n",
        "        safety_filter_level=\"BLOCK_MEDIUM_AND_ABOVE\",\n",
        "    ),\n",
        ")\n",
        "display_image(image.generated_images[0].image)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "l2p7TJtXzhpM"
      },
      "source": [
        "### View clothing image\n",
        "\n",
        "Here, you'll view the clothing image that is stored in Cloud Storage. If you'd like, you can modify the URL below to use a different image in Cloud Storage."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qj70GAQjfCPC"
      },
      "outputs": [],
      "source": [
        "clothing_image = PIL_Image.open(\n",
        "    urllib.request.urlopen(\n",
        "        \"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/dress.jpg\"\n",
        "    )\n",
        ")\n",
        "\n",
        "# Display the image\n",
        "fig, axis = plt.subplots(1, 2, figsize=(12, 6))\n",
        "axis[0].imshow(clothing_image)\n",
        "for ax in axis:\n",
        "    ax.axis(\"off\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "P-yAQ2rt_pll"
      },
      "source": [
        "### Send the request\n",
        "\n",
        "By default, a digital watermark, or [SynthID](https://deepmind.google/technologies/synthid/), is added to images. If you would like to explicitly set the watermark to True, you can do so with the `add_watermark` parameter. You can also [verify a watermarked image](https://cloud.google.com/vertex-ai/generative-ai/docs/image/verify-watermark) via Vertex AI Studio."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "c9N8l0oo_cWs"
      },
      "outputs": [],
      "source": [
        "response = client.models.recontext_image(\n",
        "    model=virtual_try_on,\n",
        "    source=RecontextImageSource(\n",
        "        person_image=image.generated_images[0].image,\n",
        "        product_images=[\n",
        "            ProductImage(\n",
        "                product_image=Image(\n",
        "                    gcs_uri=\"gs://cloud-samples-data/generative-ai/image/dress.jpg\"\n",
        "                )\n",
        "            )\n",
        "        ],\n",
        "    ),\n",
        "    config=RecontextImageConfig(\n",
        "        output_mime_type=\"image/jpeg\",\n",
        "        number_of_images=1,\n",
        "        safety_filter_level=\"BLOCK_LOW_AND_ABOVE\",\n",
        "    ),\n",
        ")\n",
        "display_image(response.generated_images[0].image)"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "name": "virtual_try_on.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
