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.
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
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 :
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
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
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
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
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.
Objectif
Modèle de prompt
Forme 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
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
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
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
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’image
Coût en tokens
Les deux dimensions de 384 px ou moins
258 tokens
Image plus grande
Découpée en tuiles de 768 x 768 px, 258 tokens par tuile
Exemple : une image qui se découpe en quatre tuiles
4 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
Limite
Valeur
Formats pris en charge
PNG, JPEG, WEBP, HEIC, HEIF
Images par requête
Jusqu’à 3 600 fichiers
Taille de requête en ligne
20 Mo au total (texte, instructions et octets)
Échelle des boîtes englobantes
0 à 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 :
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.
Joignez vos photos dans le champ Images. Le modèle accepte jusqu’à 10 images par exécution, de 7 Mo chacune.
Saisissez la consigne dans le champ Prompt, formulée exactement comme vous prévoyez de l’envoyer depuis Python.
Remplissez éventuellement System Instruction pour fixer le rôle, par exemple « Vous rédigez des textes alternatifs de moins de 125 caractères. »
Choisissez un Thinking Level parmi none, low ou high. Laissez none pour les légendes et montez-le pour un raisonnement dense.
Réglez Temperature sur une valeur basse pour l’extraction et l’OCR, et plus haute pour des légendes créatives.
Lancez, comparez la réponse à ce que vous attendiez, et ajustez la formulation avant de la copier dans le code.
Champ
Rôle
Valeur de départ
Prompt
La consigne envoyée avec les images
Votre formulation exacte de production
Images
Jusqu’à 10 fichiers, 7 Mo chacun
Une image pendant les tests
System Instruction
Définit le rôle du modèle
Une phrase courte
Thinking Level
none, low ou high
none
Temperature
Part d’aléatoire de 0 à 2
0,2 pour l’OCR, 1 pour les légendes
Max Output Tokens
Plafonne la longueur de la réponse
La 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.