Gemini API Image Understanding : envoi d’image et image vers texte en Python

Envoyez une photo à la Gemini API depuis Python et recevez du texte en retour. Cet article présente les octets en ligne, la Files API et les prompts multi-images, puis réutilise le même appel pour produire des légendes, extraire le texte de tickets de caisse (OCR) et obtenir des boîtes englobantes, avec le calcul des tokens, les limites de taille et les solutions aux erreurs courantes.

Gemini API Image Understanding : envoi d’image et image vers texte en Python
Cristian Da Conceicao
Fondateur de Picasso IA

Vous avez une photo et vous avez besoin de mots. Une photo de produit qui a besoin d’un texte alternatif, un ticket de caisse dont il faut lire le total, une étagère à compter. La Gemini API accepte l’image comme partie du prompt et renvoie du texte, si bien que tout le travail tient dans un seul appel Python d’une dizaine de lignes. Cet article suit l’ordre dans lequel les problèmes apparaissent vraiment : la configuration, trois façons d’envoyer une image, des prompts qui renvoient un texte exploitable, le coût en tokens et les erreurs qui gaspillent des requêtes.

Un changement compte pour le code ci-dessous. La documentation actuelle de Google présente l’envoi d’images via l’Interactions API (client.interactions.create) et qualifie d’ancienne (legacy) la méthode generateContent, tout en confirmant qu’elle reste pleinement prise en charge. Les deux versions figurent ici, pour que vous puissiez coller celle qui correspond à votre projet.

Ce que fait réellement l’entrée d’image

Femme tenant un téléphone au-dessus d’une photo imprimée de marché, à côté d’un ordinateur portable

Les modèles Gemini sont multimodaux, ce qui signifie qu’une seule requête peut contenir côte à côte des parties texte et des parties image. Vous envoyez une photo accompagnée d’une consigne, et le modèle répond en texte. Il n’existe pas de point d’accès distinct pour la vision, pas d’étape de prétraitement ni de bibliothèque OCR à installer au préalable. L’image n’est qu’une partie de plus du prompt.

De l’image au texte en une seule requête

Le même schéma d’appel couvre des tâches très différentes, selon la consigne que vous ajoutez :

  • Légendes : une phrase pour une publication sur les réseaux sociaux ou une description de page.
  • Texte alternatif : descriptions courtes et factuelles pour l’accessibilité.
  • Questions visuelles : « Combien de chaises y a-t-il autour de la table ? » ou « L’étiquette est-elle tournée vers l’avant ? »
  • OCR : texte extrait de tickets de caisse, de panneaux, de formulaires et de notes manuscrites.
  • Détection : boîtes englobantes étiquetées, renvoyées au format JSON.
  • Comparaison : différences entre deux images ou plus.

💡 Considérez la consigne comme le produit. Le modèle est le même dans tous les cas. Le prompt décide si vous obtenez un poème sur une photo ou un total JSON propre.

Modèles qui acceptent les images

La page des modèles de Google liste ces identifiants actuels, tous avec entrée d’image :

Identifiant du modèleStatutDescription de Google
gemini-3.8-flashStableModèle Flash le plus intelligent
gemini-3.7-flashStableCodage complexe et flux de travail agentiques
gemini-3.6-flashStableTravaux multimodaux généraux
gemini-3.5-flash (Gemini 3.5 Flash)StableCharges de travail à haut débit
gemini-3.1-pro-preview (Gemini 3.1 Pro)PréversionRésolution de problèmes complexes
gemini-3-flash-preview (Gemini 3 Flash)PréversionTâches multimodales

Les gammes de modèles évoluent vite, vérifiez donc la page des modèles avant de figer un identifiant en production. Pour le travail sur les images, un modèle Flash est le choix raisonnable par défaut. Passez à un modèle Pro seulement quand les réponses sur des numérisations denses ou des scènes délicates sont erronées.

Préparer votre environnement Python

Ordinateur portable de développeur sur un bureau en noyer, avec un terminal ouvert au crépuscule

Deux minutes de configuration aujourd’hui évitent un après-midi d’erreurs d’import déroutantes plus tard.

Installer le SDK

Le package officiel est google-genai. Les exemples ci-dessous utilisent aussi Pydantic pour la sortie structurée et Pillow pour dessiner les boîtes.

pip install -U google-genai pydantic pillow

Ne le confondez pas avec l’ancien package google-generativeai. Le nouveau s’importe sous le nom from google import genai, et tous les extraits ici le supposent.

Créer le client

Générez une clé d’API dans Google AI Studio, stockez-la dans la variable d’environnement indiquée par la page de configuration de Google, et gardez-la hors du contrôle de version. Le client la lit automatiquement :

from google import genai

client = genai.Client()

Aucun argument, aucun secret codé en dur dans le script. Chaque exemple suivant réutilise ce client.

Envoyer une image de trois façons

Choisissez la méthode selon la taille du fichier et sa réutilisation, pas par habitude.

Octets en ligne pour les petits fichiers

Fente de carte mémoire d’appareil photo, avec des tirages d’une ville portuaire derrière

Les données en ligne constituent le chemin le plus court. Vous lisez le fichier, vous l’encodez et vous l’envoyez avec le prompt. La version actuelle avec l’Interactions API ressemble à ceci :

import base64
from pathlib import Path

image_bytes = Path("street-market.jpg").read_bytes()

interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input=[
        {"type": "text", "text": "Caption this image in one sentence."},
        {
            "type": "image",
            "data": base64.b64encode(image_bytes).decode("utf-8"),
            "mime_type": "image/jpeg",
        },
    ],
)

print(interaction.output_text)

La version generateContent héritée reste valide et un peu plus courte, car le SDK gère l’encodage :

from google.genai import types

response = client.models.generate_content(
    model="gemini-3.8-flash",
    contents=[
        types.Part.from_bytes(data=image_bytes, mime_type="image/jpeg"),
        "Caption this image in one sentence.",
    ],
)

print(response.text)

Les données en ligne limitent la requête totale (texte du prompt, instructions système et octets de l’image réunis) à 20 Mo. Une photo de téléphone tient largement. Un lot de numérisations en pleine résolution, non.

La Files API pour les images plus volumineuses

Photographe à côté d’un grand tirage d’un lac de montagne, tenant un disque dur

Quand la requête dépasserait 20 Mo, ou quand vous voulez poser plusieurs questions sur une même image, importez-la une fois et référencez-la par son URI :

uploaded = client.files.upload(file="mountain-lake-print.jpg")

interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input=[
        {"type": "text", "text": "Describe the scene and list any visible text."},
        {
            "type": "image",
            "uri": uploaded.uri,
            "mime_type": uploaded.mime_type,
        },
    ],
)

print(interaction.output_text)

Les fichiers importés sont stockés temporairement, considérez donc la Files API comme un mécanisme de livraison plutôt que comme une archive. Conservez vos originaux.

Plusieurs images dans un seul prompt

Deux salons quasi identiques imprimés, avec une différence signalée

Ajoutez d’autres parties image à la même liste input. La documentation de Google autorise jusqu’à 3 600 fichiers image dans une seule requête.

before = client.files.upload(file="living-room-before.jpg")
after = client.files.upload(file="living-room-after.jpg")

interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input=[
        {
            "type": "text",
            "text": "The first image is BEFORE and the second is AFTER. "
                    "What is different between them?",
        },
        {"type": "image", "uri": before.uri, "mime_type": before.mime_type},
        {"type": "image", "uri": after.uri, "mime_type": after.mime_type},
    ],
)

print(interaction.output_text)

Indiquez dans le texte quelle image est laquelle. Le modèle voit une liste ordonnée, et un simple « compare ces images » le laisse deviner les rôles.

Des prompts qui transforment les photos en texte

L’appel ne change jamais. Seule la consigne change.

ObjectifModèle de promptForme de la sortie
Légende« Décrivez cette image en une phrase. »Texte brut
Texte alternatif« Rédigez un texte alternatif de moins de 125 caractères. Décrivez uniquement ce qui est visible. »Texte brut
Question visuelle« Combien de caisses rouges se trouvent sur l’étagère de gauche ? »Réponse courte
Extraction« Extrayez le commerçant, la date et le total. »JSON via schéma
Détection« Détectez tous les éléments principaux de l’image. »JSON via schéma

Légendes et texte alternatif

Éditeur web rédigeant un texte alternatif dans un carnet, à côté d’un écran

Le plus gros gain de qualité vient des contraintes. « Décrivez cette image » renvoie un paragraphe. « Rédigez un texte alternatif de moins de 125 caractères, sans formule d’ouverture du type « image de » » renvoie un texte publiable.

prompt = (
    "Write alt text for this photo in under 125 characters. "
    "Describe only what is visible. Do not start with 'image of'."
)

Lancez cela sur un dossier de photos avec une boucle simple, et vous obtenez un premier jet de chaque attribut alt manquant sur un site. Un humain doit tout de même relire les brouillons, car un modèle peut mal juger ce qui compte dans une scène.

OCR et tickets de caisse

Tickets de caisse froissés et liste manuscrite sur le comptoir d’un café

Les tickets de caisse sont un bon test, car ils mêlent texte imprimé, chiffres et plis. Demandez une sortie structurée plutôt qu’une réponse en prose. Définissez la forme avec Pydantic et transmettez son schéma JSON via response_format :

from pydantic import BaseModel

class LineItem(BaseModel):
    name: str
    price: float

class Receipt(BaseModel):
    merchant: str
    date: str
    items: list[LineItem]
    total: float

receipt = client.files.upload(file="receipt.jpg")

interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input=[
        {
            "type": "text",
            "text": "Extract the merchant, date, line items, and total.",
        },
        {"type": "image", "uri": receipt.uri, "mime_type": receipt.mime_type},
    ],
    response_format={
        "type": "text",
        "mime_type": "application/json",
        "schema": Receipt.model_json_schema(),
    },
)

data = Receipt.model_validate_json(interaction.output_text)
print(data.merchant, data.total)

Si le modèle renvoie quelque chose qui ne correspond pas au schéma, model_validate_json lève une erreur immédiatement, au lieu de laisser des données erronées s’infiltrer dans votre base.

Détection d’objets avec des boîtes

Rayon d’épicerie avec des caisses d’oranges, de tomates et de poivrons

Gemini peut renvoyer des boîtes englobantes sous la forme [ymin, xmin, ymax, xmax], normalisées sur une échelle de 0 à 1000. Demandez-les avec un schéma, puis convertissez en pixels et dessinez :

from PIL import Image, ImageDraw
from pydantic import BaseModel, Field

class Box(BaseModel):
    box_2d: list[int] = Field(
        description="[ymin, xmin, ymax, xmax] normalized to 0-1000."
    )
    label: str

class Boxes(BaseModel):
    boxes: list[Box]

aisle = client.files.upload(file="grocery-aisle.jpg")

interaction = client.interactions.create(
    model="gemini-3.8-flash",
    input=[
        {"type": "text", "text": "Detect all of the prominent items in the image."},
        {"type": "image", "uri": aisle.uri, "mime_type": aisle.mime_type},
    ],
    response_format={
        "type": "text",
        "mime_type": "application/json",
        "schema": Boxes.model_json_schema(),
    },
)

result = Boxes.model_validate_json(interaction.output_text)

image = Image.open("grocery-aisle.jpg")
width, height = image.size
draw = ImageDraw.Draw(image)

for item in result.boxes:
    ymin, xmin, ymax, xmax = item.box_2d
    left, top = xmin / 1000 * width, ymin / 1000 * height
    right, bottom = xmax / 1000 * width, ymax / 1000 * height
    draw.rectangle((left, top, right, bottom), outline="red", width=4)
    draw.text((left + 6, top + 6), item.label, fill="red")

image.save("grocery-aisle-boxes.jpg")

La segmentation suit le même schéma. Le schéma ajoute un champ mask contenant les points du polygone, également normalisés sur 0 à 1000. Google recommande de régler le niveau de réflexion sur minimal pour la segmentation, car la réflexion étendue ajoute de la latence sans améliorer les polygones.

Limites, tokens et coûts

Planche-contact de petites vues sur une table lumineuse avec une loupe

Les images sont facturées en tokens, et leur nombre dépend de la taille. Connaître la règle vous permet d’estimer la facture avant le lancement du lot.

Comment les images se comptent en tokens

Situation de l’imageCoût en tokens
Les deux dimensions de 384 px ou moins258 tokens
Image plus grandeDécoupée en tuiles de 768 x 768 px, 258 tokens par tuile
Exemple : une image qui se découpe en quatre tuiles4 x 258 = 1 032 tokens

La documentation décrit aussi un réglage media_resolution qui plafonne le nombre maximal de tokens alloués à chaque image d’entrée. Abaissez-le pour les légendes en masse, lorsque les détails fins sont sans importance. Augmentez-le quand les petits caractères ou les objets lointains comptent. Vérifiez la référence actuelle pour savoir comment votre version du SDK nomme l’option.

Les tarifs varient selon le modèle, consultez donc la page des tarifs de Google pour les chiffres. Le levier que vous contrôlez est le nombre de tokens, et envoyer une copie plus petite du fichier est le moyen le moins cher de le réduire.

Limites de format et de taille

LimiteValeur
Formats pris en chargePNG, JPEG, WEBP, HEIC, HEIF
Images par requêteJusqu’à 3 600 fichiers
Taille de requête en ligne20 Mo au total (texte, instructions et octets)
Échelle des boîtes englobantes0 à 1000, ordre [ymin, xmin, ymax, xmax]

💡 Si un travail envoie de nombreuses images avec un prompt long, calculez le total en ligne avant d’atteindre la limite de 20 Mo. Passer à la Files API en cours de projet est facile, mais le faire tôt évite un échec capricieux à 2 h du matin.

Trois erreurs qui gaspillent des appels

La plupart des requêtes échouées viennent de la même courte liste.

Mauvais type MIME

Le mime_type doit correspondre au fichier réel. Étiqueter un PNG comme image/jpeg, ou passer un format non pris en charge, produit des erreurs ou de mauvais résultats. Laissez Python déterminer le type au lieu de saisir les chaînes à la main :

import mimetypes

def mime_for(path: str) -> str:
    mime, _ = mimetypes.guess_type(path)
    if mime is None:
        raise ValueError(f"Unknown image type: {path}")
    return mime

Certains systèmes ne connaissent pas le type HEIC, ajoutez donc une petite correspondance manuelle si vous acceptez les originaux d’iPhone.

Boîtes au mauvais endroit

Si les rectangles dessinés tombent à des endroits bizarres, vérifiez deux choses. D’abord, l’ordre est [ymin, xmin, ymax, xmax], avec la valeur verticale en premier. Beaucoup de gens le lisent comme x puis y. Ensuite, les nombres sont sur une échelle de 0 à 1000, et non en pixels. Divisez par 1000, puis multipliez par la largeur ou la hauteur réelle.

Du texte libre là où il faut du JSON

Écrire « renvoie du JSON » dans le prompt fonctionne jusqu’au moment où le modèle enveloppe la réponse dans un bloc de code ou ajoute une phrase aimable. Transmettez un schéma via response_format et analysez avec model_validate_json. Le contrat vit alors dans le code, où une mauvaise réponse échoue bruyamment et une bonne arrive typée.

Essayer Gemini 3.5 Flash sans code

Avant d’écrire du Python, testez le prompt dans un navigateur. Gemini 3.5 Flash fonctionne sur Picasso IA et accepte directement les images, vous pouvez donc ajuster une consigne en quelques secondes et la coller ensuite dans votre script.

  1. Ouvrez la page Gemini 3.5 Flash sur Picasso IA.
  2. Joignez vos photos dans le champ Images. Le modèle accepte jusqu’à 10 images par exécution, de 7 Mo chacune.
  3. Saisissez la consigne dans le champ Prompt, formulée exactement comme vous prévoyez de l’envoyer depuis Python.
  4. Remplissez éventuellement System Instruction pour fixer le rôle, par exemple « Vous rédigez des textes alternatifs de moins de 125 caractères. »
  5. Choisissez un Thinking Level parmi none, low ou high. Laissez none pour les légendes et montez-le pour un raisonnement dense.
  6. Réglez Temperature sur une valeur basse pour l’extraction et l’OCR, et plus haute pour des légendes créatives.
  7. Lancez, comparez la réponse à ce que vous attendiez, et ajustez la formulation avant de la copier dans le code.
ChampRôleValeur de départ
PromptLa consigne envoyée avec les imagesVotre formulation exacte de production
ImagesJusqu’à 10 fichiers, 7 Mo chacunUne image pendant les tests
System InstructionDéfinit le rôle du modèleUne phrase courte
Thinking Levelnone, low ou highnone
TemperaturePart d’aléatoire de 0 à 20,2 pour l’OCR, 1 pour les légendes
Max Output TokensPlafonne la longueur de la réponseLa valeur par défaut convient

Les limites sur Picasso IA diffèrent des limites brutes de l’API ci-dessus, considérez donc la page comme un laboratoire de prompts et l’API comme la voie de production. Pour un second avis sur une image difficile, lancez le même prompt avec Gemini 3.1 Pro, Qwen3.7-Plus, qui interprète les images aussi bien que le texte, ou Granite Vision 4.1 4B, conçu pour les graphiques et les tableaux.

Créer vos propres images de test

Vous n’avez pas besoin d’un dossier de vraies photos pour commencer. Générez un bureau en désordre, un rayon d’épicerie, une rue sous la pluie ou un ticket froissé avec PicassoIA Image ou Seedream 4.5, puis soumettez chaque résultat à Gemini 3.5 Flash et voyez ce qu’il en lit.

Essayez trois expériences cette semaine. Demandez un texte alternatif pour cinq photos générées. Demandez une boîte englobante autour d’un objet dans une scène chargée. Demandez un total JSON à partir d’une image de ticket. Chacune prend quelques minutes, et ensemble elles montrent où le modèle est précis et où votre prompt doit être resserré.

Ouvrez Picasso IA, créez votre première image de test et lancez votre propre prompt. Parcourez tous les modèles disponibles sur picassoia.com/en/all-models et associez un générateur d’images à un modèle de vision pour construire votre propre flux de travail d’image vers texte.

Partager cet article

Choisissez votre langue