Cómo llamar a Google Nano Banana para recortar fondos de imágenes

A partir de un script Python ejecutable, explica cómo llamar a Google Nano Banana para recortar fondos en imágenes de producto y conserva el código fuente completo.

Este artículo usa un script Python realmente ejecutable para demostrar cómo llamar a la capacidad de edición de imágenes Nano Banana de Google y recortar fondos de imágenes de producto.

El objetivo de esta implementación es muy claro:

  • Leer imágenes de producto desde un directorio
  • Llamar al modelo de imagen de Google para eliminar el fondo
  • Hacer una limpieza local adicional del fondo transparente sobre la imagen devuelta
  • Exportar finalmente como PNG con fondo transparente

Si ya tienes un lote de imágenes de producto con fondo blanco, fotos de auriculares o cables, y quieres generar rápidamente imágenes de fondo transparente aptas para e-commerce, esta forma es bastante directa.

Qué hace este código

Este script se divide principalmente en 4 partes:

  1. Definir el prompt para que el modelo sepa que debe “quitar fondo, conservar sujeto, no añadir sombras”
  2. Llamar a la interfaz de generación de imágenes de google-genai
  3. Extraer el resultado de imagen desde la respuesta del modelo
  4. Usar lógica local para convertir fondos claros de los bordes en transparencia, reduciendo restos de borde

Es decir, no se limita a enviar una imagen al modelo y terminar, sino que encadena “edición con modelo + posprocesamiento local”.

Preparación antes de ejecutar

Primero instala dependencias:

1
.\.venv\Scripts\python.exe -m pip install google-genai pillow

Cómo obtener GEMINI_API_KEY

GEMINI_API_KEY es la clave usada para llamar a Gemini API. Según el quickstart oficial de Google, si todavía no tienes una key, puedes crearla directamente en Google AI Studio.

Pasos:

  1. Abre Google AI Studio.
  2. Inicia sesión con tu cuenta de Google.
  3. Busca la página Get API key o API keys.
  4. Crea una nueva API key.
  5. Copia la key generada.
  6. Configúrala como variable de entorno local para que el script pueda leerla.

Si la página todavía no tiene un proyecto disponible, normalmente hay que completar primero la inicialización del proyecto y después volver a la página de API Key para crear la clave.

Después de obtener la key, configura la variable de entorno:

1
$env:GEMINI_API_KEY="your_api_key"

Si usas cmd, puedes escribir:

1
set GEMINI_API_KEY=your_api_key

Si configuras a la vez GEMINI_API_KEY y GOOGLE_API_KEY, en ejecución normalmente se leerá primero GOOGLE_API_KEY, así que se recomienda conservar solo una para evitar confusión.

Ejemplo de estructura de directorios

El script recibe dos parámetros:

  • input_dir: directorio de imágenes de entrada
  • output_dir: directorio de imágenes de salida

Por ejemplo:

1
2
3
4
5
images/
  product1.jpg
  product2.png

output/

Cómo ejecutarlo

Suponiendo que el script se llame cutout.py, se ejecuta así:

1
.\.venv\Scripts\python.exe .\cutout.py .\images .\output

Si quieres cambiar de modelo, también puedes pasar el parámetro explícitamente:

1
.\.venv\Scripts\python.exe .\cutout.py .\images .\output --model gemini-2.5-flash-image

El script recorrerá estos formatos dentro del directorio de entrada:

  • .jpg
  • .jpeg
  • .png
  • .webp

Al terminar, generará archivos PNG con fondo transparente y el mismo nombre en el directorio de salida.

Flujo principal de llamada

La llamada clave a Google Nano Banana está aquí:

1
2
3
4
response = client.models.generate_content(
    model=model,
    contents=[PROMPT, image],
)

Aquí se pasan dos contenidos:

  • Un prompt de texto PROMPT
  • Una imagen PIL.Image

El prompt le pide al modelo eliminar el fondo completo de la imagen de producto, conservar solo el sujeto y enfatiza varios puntos:

  • Conservar el producto completo
  • Conservar detalles de cables y líneas finas
  • Limpiar huecos internos y zonas anulares
  • No añadir objetos nuevos
  • No añadir sombras

Este tipo de prompt influye mucho en la calidad del recorte, especialmente en detalles como cables de auriculares, bordes transparentes y zonas huecas.

Por qué hacer otro posprocesamiento local

Después de que el modelo devuelve el resultado, el script no lo guarda directamente, sino que ejecuta make_transparent_from_borders(image).

La idea de este paso es:

  • Buscar píxeles de fondo claros desde los bordes de la imagen
  • Usar búsqueda en anchura para marcar todas las zonas claras conectadas
  • Convertir finalmente esas zonas en transparentes

La ventaja es que puede limpiar mejor algunos bordes blancos residuales, fondos gris claro y zonas de borde poco limpias.

La condición para decidir “si es fondo” está aquí:

1
2
3
4
def is_light_background_pixel(r: int, g: int, b: int) -> bool:
    brightness = (r + g + b) / 3
    spread = max(r, g, b) - min(r, g, b)
    return brightness >= 170 and spread <= 35

En términos simples:

  • El color debe ser suficientemente claro
  • La diferencia entre los tres canales RGB no debe ser grande

Esto encaja bien con fondos blancos, gris claro o casi de color sólido en imágenes de producto.

Código fuente completo

Abajo se conserva el código fuente completo actual, para que puedas reutilizarlo o modificarlo directamente:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
from __future__ import annotations

import argparse
import os
from pathlib import Path
from collections import deque

from PIL import Image

try:
    from google import genai
except ImportError as exc:  # pragma: no cover
    raise SystemExit(
        "Missing dependency: google-genai. Install it with "
        r"'.\.venv\Scripts\python.exe -m pip install google-genai'."
    ) from exc


PROMPT = (
    "Remove the entire background from this product photo and return only the product "
    "on a fully transparent background as a PNG. Keep the full product intact, preserve "
    "thin cable details, clean the inner loops and holes, and do not add any new objects "
    "or shadows."
)


def is_light_background_pixel(r: int, g: int, b: int) -> bool:
    brightness = (r + g + b) / 3
    spread = max(r, g, b) - min(r, g, b)
    return brightness >= 170 and spread <= 35


def to_pil_image(image_obj) -> Image.Image:
    if isinstance(image_obj, Image.Image):
        return image_obj
    pil_image = getattr(image_obj, "_pil_image", None)
    if isinstance(pil_image, Image.Image):
        return pil_image
    as_pil = getattr(image_obj, "pil_image", None)
    if isinstance(as_pil, Image.Image):
        return as_pil
    raise TypeError(f"Unsupported image object type: {type(image_obj)!r}")


def make_transparent_from_borders(image: Image.Image) -> Image.Image:
    rgba = image.convert("RGBA")
    width, height = rgba.size
    pixels = rgba.load()

    visited: set[tuple[int, int]] = set()
    queue: deque[tuple[int, int]] = deque()

    def push_if_bg(x: int, y: int) -> None:
        if (x, y) in visited:
            return
        r, g, b, _ = pixels[x, y]
        if is_light_background_pixel(r, g, b):
            visited.add((x, y))
            queue.append((x, y))

    for x in range(width):
        push_if_bg(x, 0)
        push_if_bg(x, height - 1)
    for y in range(height):
        push_if_bg(0, y)
        push_if_bg(width - 1, y)

    while queue:
        x, y = queue.popleft()
        for nx, ny in ((x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)):
            if 0 <= nx < width and 0 <= ny < height:
                push_if_bg(nx, ny)

    for x, y in visited:
        pixels[x, y] = (0, 0, 0, 0)

    return rgba


def save_first_image_part(response, dst: Path) -> None:
    parts = getattr(response, "parts", None)
    if parts is None and getattr(response, "candidates", None):
        parts = response.candidates[0].content.parts

    if not parts:
        raise RuntimeError("Model returned no content parts.")

    for part in parts:
        inline_data = getattr(part, "inline_data", None)
        if inline_data is None and isinstance(part, dict):
            inline_data = part.get("inline_data")

        if inline_data is None:
            continue

        if hasattr(part, "as_image"):
            image = to_pil_image(part.as_image())
            dst.parent.mkdir(parents=True, exist_ok=True)
            make_transparent_from_borders(image).save(dst)
            return

        data = getattr(inline_data, "data", None)
        mime_type = getattr(inline_data, "mime_type", "")
        if data:
            dst.parent.mkdir(parents=True, exist_ok=True)
            with open(dst, "wb") as handle:
                handle.write(data)
            with Image.open(dst) as img:
                processed = make_transparent_from_borders(img)
                processed.save(dst.with_suffix(".png"))
            if dst.suffix.lower() != ".png":
                dst.unlink(missing_ok=True)
            return

    raise RuntimeError("Model returned text only and no edited image.")


def process_image(src: Path, dst: Path, client, model: str) -> None:
    with Image.open(src).convert("RGBA") as image:
        response = client.models.generate_content(
            model=model,
            contents=[PROMPT, image],
        )
    save_first_image_part(response, dst)


def main() -> None:
    parser = argparse.ArgumentParser(description="Use Nano Banana / Gemini image editing to cut out product images.")
    parser.add_argument("input_dir", type=Path)
    parser.add_argument("output_dir", type=Path)
    parser.add_argument("--model", default="gemini-2.5-flash-image")
    args = parser.parse_args()

    api_key = os.environ.get("GEMINI_API_KEY")
    if not api_key:
        raise SystemExit("Missing GEMINI_API_KEY environment variable.")

    client = genai.Client(api_key=api_key)
    exts = {".jpg", ".jpeg", ".png", ".webp"}

    for src in sorted(args.input_dir.iterdir()):
        if not src.is_file() or src.suffix.lower() not in exts:
            continue
        dst = args.output_dir / f"{src.stem}.png"
        process_image(src, dst, client, args.model)
        print(dst)


if __name__ == "__main__":
    main()

Qué conviene optimizar después

Si quieres seguir usando este script para producción por lotes, después puedes añadir:

  • Reintentos ante fallos, para evitar que una sola imagen rompa todo el lote
  • Registro de logs, para localizar qué imagen falló
  • Umbrales configurables para distintos fondos
  • Escaneo recursivo de subdirectorios
  • Vista previa comparativa entre imagen original y resultado

Resumen

Si solo quieres entender rápido “cómo llamar a Google Nano Banana para recortar fondos”, el núcleo son tres pasos:

  1. Instalar google-genai y Pillow
  2. Configurar GEMINI_API_KEY
  3. Usar client.models.generate_content() pasando prompt e imagen

El valor de este código está en que no solo llama al modelo, sino que añade posprocesamiento de fondo transparente, por lo que sirve mejor para tareas reales de recorte de imágenes de producto.

记录并分享
Creado con Hugo
Tema Stack diseñado por Jimmy