Aller au contenu principal

Éditer des images existantes (inpainting, outpainting)

Éditer des images existantes

La méthode client.images.edit() vous permet de modifier des images existantes en utilisant un masque pour définir la zone à régénérer. Cette technique couvre deux cas principaux : l’inpainting (remplir ou remplacer une zone intérieure) et l’outpainting (étendre l’image au-delà de ses bordures).

Principe du masque

Le masque est une image PNG de la même taille que l’image source. Les zones transparentes (alpha = 0) indiquent où le modèle doit générer du nouveau contenu. Les zones opaques restent intactes.

from openai import OpenAI

client = OpenAI()

response = client.images.edit(
    model="gpt-image-1",
    image=open("photo_bureau.png", "rb"),
    mask=open("masque_bureau.png", "rb"),
    prompt="Un écran d'ordinateur affichant un tableau de bord analytics moderne"
)

print(response.data[0].url)

Créer un masque programmatiquement

Vous pouvez générer des masques avec Pillow sans passer par un éditeur graphique :

from PIL import Image, ImageDraw

# Charger l'image source pour obtenir ses dimensions
source = Image.open("photo_bureau.png")
width, height = source.size

# Créer un masque entièrement opaque (noir)
mask = Image.new("RGBA", (width, height), (0, 0, 0, 255))
draw = ImageDraw.Draw(mask)

# Dessiner une zone transparente (la zone à éditer)
# Rectangle au centre de l'image
x1, y1 = width // 4, height // 4
x2, y2 = 3 * width // 4, 3 * height // 4
draw.rectangle([x1, y1, x2, y2], fill=(0, 0, 0, 0))

mask.save("masque_bureau.png")
print(f"Masque créé : {width}x{height}, zone éditable au centre")

Inpainting : remplacer un élément

L’inpainting consiste à remplacer une partie spécifique de l’image. Le prompt décrit ce qui doit apparaître dans la zone masquée.

from openai import OpenAI
from PIL import Image, ImageDraw
import base64

client = OpenAI()

def inpaint_region(image_path, region, prompt, output_path):
    """
    Remplace une région rectangulaire dans une image.
    region : tuple (x1, y1, x2, y2) en pixels
    """
    # Créer le masque
    source = Image.open(image_path)
    mask = Image.new("RGBA", source.size, (0, 0, 0, 255))
    draw = ImageDraw.Draw(mask)
    draw.rectangle(region, fill=(0, 0, 0, 0))
    mask.save("temp_mask.png")

    # Appeler l'API
    response = client.images.edit(
        model="gpt-image-1",
        image=open(image_path, "rb"),
        mask=open("temp_mask.png", "rb"),
        prompt=prompt
    )

    # Sauvegarder le résultat
    import urllib.request
    urllib.request.urlretrieve(response.data[0].url, output_path)
    print(f"Image éditée sauvegardée : {output_path}")


# Exemple : remplacer le ciel dans une photo de paysage
inpaint_region(
    image_path="paysage.png",
    region=(0, 0, 1024, 400),  # partie supérieure = le ciel
    prompt="Ciel dramatique avec des nuages d'orage violets au coucher du soleil",
    output_path="paysage_ciel_modifie.png"
)

Outpainting : étendre l’image

L’outpainting consiste à agrandir l’image en générant du contenu autour de l’original. La technique repose sur le placement de l’image source dans un canvas plus grand.

from openai import OpenAI
from PIL import Image
import base64
from io import BytesIO

client = OpenAI()

def outpaint(image_path, direction, extra_pixels, prompt, output_path):
    """
    Étend une image dans une direction donnée.
    direction : 'right', 'bottom', 'left', 'top'
    extra_pixels : nombre de pixels à ajouter
    """
    source = Image.open(image_path).convert("RGBA")
    w, h = source.size

    # Calculer les nouvelles dimensions
    if direction == "right":
        new_size = (w + extra_pixels, h)
        paste_pos = (0, 0)
    elif direction == "bottom":
        new_size = (w, h + extra_pixels)
        paste_pos = (0, 0)
    elif direction == "left":
        new_size = (w + extra_pixels, h)
        paste_pos = (extra_pixels, 0)
    elif direction == "top":
        new_size = (w, h + extra_pixels)
        paste_pos = (0, extra_pixels)

    # Créer le canvas étendu (transparent = zone à générer)
    extended = Image.new("RGBA", new_size, (0, 0, 0, 0))
    extended.paste(source, paste_pos)

    # Le masque : transparent partout sauf où l'image originale est placée
    mask = Image.new("RGBA", new_size, (0, 0, 0, 0))
    opaque = Image.new("RGBA", (w, h), (0, 0, 0, 255))
    mask.paste(opaque, paste_pos)

    # Sauvegarder temporairement
    extended.save("temp_extended.png")
    mask.save("temp_mask_outpaint.png")

    response = client.images.edit(
        model="gpt-image-1",
        image=open("temp_extended.png", "rb"),
        mask=open("temp_mask_outpaint.png", "rb"),
        prompt=prompt
    )

    import urllib.request
    urllib.request.urlretrieve(response.data[0].url, output_path)
    print(f"Image étendue sauvegardée : {output_path}")


# Étendre un portrait vers la droite
outpaint(
    image_path="portrait.png",
    direction="right",
    extra_pixels=512,
    prompt="Continuation naturelle de la scène, même éclairage et arrière-plan",
    output_path="portrait_etendu.png"
)

Édition itérative

Vous pouvez enchaîner plusieurs éditions sur la même image :

from openai import OpenAI
import urllib.request

client = OpenAI()

def edit_step(image_path, mask_path, prompt, output_path):
    response = client.images.edit(
        model="gpt-image-1",
        image=open(image_path, "rb"),
        mask=open(mask_path, "rb"),
        prompt=prompt
    )
    urllib.request.urlretrieve(response.data[0].url, output_path)
    return output_path

# Étape 1 : modifier l'arrière-plan
step1 = edit_step(
    "scene.png", "mask_background.png",
    "Arrière-plan de forêt tropicale luxuriante",
    "scene_step1.png"
)

# Étape 2 : ajouter un élément au premier plan
step2 = edit_step(
    step1, "mask_foreground.png",
    "Un perroquet ara coloré posé sur une branche",
    "scene_step2.png"
)

print(f"Résultat final : {step2}")

Contraintes à connaître

  • L’image source et le masque doivent avoir les mêmes dimensions
  • Les deux fichiers doivent être au format PNG
  • La taille maximale par fichier est de 4 Mo
  • Le masque utilise le canal alpha pour définir les zones éditables
  • Les résultats sont plus cohérents quand la zone masquée représente moins de 50 % de l’image

Exercice pratique

Prenez une photo de votre bureau (ou toute image libre de droits). Créez un script qui :

  1. Génère automatiquement un masque sur le quart supérieur de l’image
  2. Remplace cette zone par un ciel étoilé
  3. Sauvegarde le résultat en local