Gemini API Image Understanding: entrada de imagem e imagem para texto em Python
Envie uma foto para a API do Gemini a partir do Python e receba texto de volta. Este artigo mostra bytes inline, a Files API e prompts com várias imagens, depois transforma a mesma chamada em legendas, OCR de recibos e caixas delimitadoras, com cálculo de tokens, limites de tamanho e correções para erros comuns.
Você tem uma foto e precisa de palavras. Uma imagem de produto que precisa de texto alternativo, um recibo que precisa do total, uma prateleira que precisa de contagem. A API do Gemini aceita a imagem como parte do prompt e devolve texto, então todo o trabalho cabe em uma única chamada em Python de cerca de dez linhas. Este artigo segue a ordem em que os problemas realmente aparecem: configuração, três formas de enviar uma imagem, prompts que retornam texto utilizável, custos em tokens e os erros que desperdiçam requisições.
Uma mudança importa para o código abaixo. A documentação atual do Google mostra a entrada de imagem pela Interactions API (client.interactions.create) e marca o método mais antigo, generateContent, como legado, embora confirme que ele continua totalmente suportado. As duas versões aparecem aqui, para que você possa colar a que corresponde ao seu projeto.
O que a entrada de imagem faz de fato
Os modelos Gemini são multimodais, o que significa que uma única requisição pode conter partes de texto e partes de imagem lado a lado. Você envia uma foto mais uma instrução, e o modelo responde em texto. Não há endpoint de visão separado, nenhuma etapa de pré-processamento e nenhuma biblioteca de OCR para instalar antes. A imagem é apenas mais uma parte do prompt.
Imagem para texto em uma requisição
O mesmo padrão de chamada resolve trabalhos bem diferentes, dependendo da instrução que você anexa:
Legendagem: uma frase para uma postagem em redes sociais ou a descrição de uma página.
Texto alternativo: descrições curtas e literais para acessibilidade.
Perguntas visuais: "Quantas cadeiras há na mesa?" ou "O rótulo está virado para frente?"
OCR: texto extraído de recibos, placas, formulários e anotações manuscritas.
Detecção: caixas delimitadoras com rótulos, retornadas como JSON.
Comparação: diferenças entre duas ou mais imagens.
💡 Trate a instrução como o produto. O modelo é o mesmo em todos os casos. O prompt decide se você recebe um poema sobre uma foto ou um total limpo em JSON.
Modelos que aceitam imagens
A página de modelos do Google lista estes IDs atuais, todos com entrada de imagem:
ID do modelo
Status
Descrição do Google
gemini-3.8-flash
Estável
Modelo Flash mais inteligente
gemini-3.7-flash
Estável
Programação complexa e fluxos de trabalho agênticos
As linhas de modelos mudam rápido, então confira a página de modelos antes de fixar um ID em produção. Para trabalho com imagens, um modelo Flash é o padrão sensato. Passe para um modelo Pro somente quando as respostas sobre digitalizações densas ou cenas complicadas vierem erradas.
Configure seu ambiente Python
Dois minutos de configuração agora economizam uma tarde de erros de importação confusos depois.
Instale o SDK
O pacote oficial é google-genai. Os exemplos abaixo também usam Pydantic para saída estruturada e Pillow para desenhar as caixas.
pip install -U google-genai pydantic pillow
Não confunda com o pacote google-generativeai, mais antigo. O novo é importado como from google import genai, e todos os trechos aqui partem dele.
Crie o cliente
Gere uma credencial no Google AI Studio, armazene-a na variável de ambiente indicada na página de configuração do Google e mantenha-a fora do controle de versão. O cliente a lê automaticamente:
from google import genai
client = genai.Client()
Sem argumentos, sem segredos fixos no script. Todo exemplo a seguir reutiliza este client.
Envie uma imagem de três formas
Escolha o método pelo tamanho do arquivo e pelo reuso, não pelo hábito.
Bytes inline para arquivos pequenos
Os dados inline são o caminho mais curto. Você lê o arquivo, codifica e envia junto com o prompt. A versão atual da Interactions API fica assim:
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)
A versão generateContent legada continua válida e um pouco mais curta, porque o SDK cuida da codificação:
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)
Os dados inline limitam o total da requisição (texto do prompt, instruções do sistema e bytes da imagem somados) a 20 MB. Uma foto de celular cabe com folga. Um lote de digitalizações em resolução total não cabe.
Files API para imagens maiores
Quando a requisição ultrapassaria 20 MB, ou quando você quer fazer várias perguntas sobre a mesma imagem, envie o arquivo uma vez e referencie-o pela 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)
Os arquivos enviados ficam armazenados temporariamente, então trate a Files API como um mecanismo de entrega, não como arquivo morto. Guarde seus originais.
Várias imagens em um prompt
Adicione mais partes de imagem à mesma lista input. A documentação do Google permite até 3.600 arquivos de imagem em uma requisição.
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)
Diga no texto qual imagem é qual. O modelo vê uma lista ordenada, e um simples "compare estas" o deixa adivinhando os papéis.
Prompts que transformam fotos em texto
A chamada nunca muda. Só a instrução muda.
Objetivo
Padrão do prompt
Formato da saída
Legenda
"Legende esta imagem em uma frase."
Texto simples
Texto alternativo
"Escreva um texto alternativo com menos de 125 caracteres. Descreva apenas o que está visível."
Texto simples
Pergunta visual
"Quantas caixas vermelhas há na prateleira da esquerda?"
Resposta curta
Extração
"Extraia estabelecimento, data e total."
JSON via schema
Detecção
"Detecte todos os itens de destaque na imagem."
JSON via schema
Legendas e texto alternativo
O maior ganho de qualidade vem das restrições. "Descreva esta imagem" retorna um parágrafo. "Escreva um texto alternativo com menos de 125 caracteres, sem frase de abertura como 'imagem de'" retorna algo que você pode publicar.
prompt = (
"Write alt text for this photo in under 125 characters. "
"Describe only what is visible. Do not start with 'image of'."
)
Rode isso sobre uma pasta de fotos com um laço simples e você terá um primeiro rascunho de cada atributo alt que falta em um site. Uma pessoa ainda precisa ler os rascunhos, porque um modelo pode julgar mal o que importa em uma cena.
OCR e recibos
Recibos são um bom teste porque misturam texto impresso, números e dobras. Peça saída estruturada em vez de prosa. Defina o formato com Pydantic e passe seu JSON schema por meio de 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)
Se o modelo retornar algo que não se encaixa no schema, model_validate_json gera um erro ali mesmo, em vez de deixar dados ruins escorregarem para o seu banco de dados.
Detecção de objetos com caixas
O Gemini pode retornar caixas delimitadoras como [ymin, xmin, ymax, xmax], normalizadas em uma escala de 0 a 1000. Peça-as com um schema, depois converta para pixels e desenhe:
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")
A segmentação segue o mesmo padrão. O schema adiciona um campo mask com os pontos do polígono, também normalizados de 0 a 1000. O Google recomenda definir o nível de raciocínio como minimal para segmentação, já que o raciocínio estendido adiciona latência sem melhorar os polígonos.
Limites, tokens e custos
As imagens são cobradas em tokens, e a contagem depende do tamanho. Conhecer a regra permite prever a cobrança antes do lote rodar.
Como as imagens contam como tokens
Situação da imagem
Custo em tokens
Ambas as dimensões com 384 px ou menos
258 tokens
Imagem maior
Dividida em blocos de 768 x 768 px, 258 tokens por bloco
Exemplo: uma imagem que se divide em quatro blocos
4 x 258 = 1.032 tokens
A documentação também descreve uma configuração media_resolution que limita o número máximo de tokens alocados a cada imagem de entrada. Reduza-a em legendagem em massa, quando detalhes finos não importam. Aumente-a quando letras pequenas ou objetos distantes forem relevantes. Confira a referência atual para saber como a sua versão do SDK escreve a opção.
O preço varia por modelo, então consulte a página de preços do Google para ver os números. A alavanca que você controla é a contagem de tokens, e enviar uma cópia menor do arquivo é a forma mais barata de reduzi-la.
Limites de formato e tamanho
Limite
Valor
Formatos suportados
PNG, JPEG, WEBP, HEIC, HEIF
Imagens por requisição
Até 3.600 arquivos
Tamanho da requisição inline
20 MB no total (texto, instruções e bytes)
Escala das caixas delimitadoras
0 a 1000, ordem [ymin, xmin, ymax, xmax]
💡 Se um trabalho envia muitas imagens com um prompt longo, some o total inline antes de bater no limite de 20 MB. Mudar para a Files API no meio do projeto é fácil, mas fazer isso cedo evita uma falha intermitente às 2 da manhã.
Três erros que desperdiçam chamadas
A maioria das requisições com falha vem da mesma lista curta.
Tipo MIME errado
O mime_type precisa corresponder ao arquivo real. Rotular um PNG como image/jpeg ou enviar um formato não suportado gera erros ou resultados ruins. Deixe o Python decidir em vez de digitar strings à mão:
Alguns sistemas não reconhecem o tipo HEIC, então acrescente um pequeno mapeamento manual se você aceita originais de iPhone.
Caixas no lugar errado
Se os retângulos desenhados caem em lugares estranhos, verifique duas coisas. Primeiro, a ordem é [ymin, xmin, ymax, xmax], com o valor vertical primeiro. Muita gente lê como x e depois y. Segundo, os números estão em uma escala de 0 a 1000, não em pixels. Divida por 1000 e depois multiplique pela largura ou altura reais.
Texto livre onde deveria haver JSON
Escrever "retorne JSON" no prompt funciona até o modelo envolver a resposta em um bloco de código ou acrescentar uma frase simpática. Passe um schema por meio de response_format e interprete com model_validate_json. O contrato passa a viver no código, onde uma resposta ruim falha de forma explícita e uma boa chega tipada.
Experimente o Gemini 3.5 Flash sem código
Antes de escrever Python, teste o prompt no navegador. O Gemini 3.5 Flash roda no PicassoIA e aceita imagens diretamente, então você pode ajustar uma instrução em segundos e colá-la no seu script depois.
Anexe suas fotos no campo Images. O modelo aceita até 10 imagens por execução, cada uma com até 7 MB.
Digite a instrução no campo Prompt, com a redação exata que você pretende enviar pelo Python.
Opcionalmente, preencha System Instruction para fixar o papel, como "Você escreve textos alternativos com menos de 125 caracteres."
Escolha um Thinking Level entre none, low ou high. Deixe em none para legendas e aumente para raciocínio denso.
Defina Temperature baixa para extração e OCR, e mais alta para legendas criativas.
Execute, compare a resposta com o que você queria e ajuste a redação antes de copiar para o código.
Campo
O que faz
Valor inicial
Prompt
A instrução enviada com as imagens
Sua redação exata de produção
Images
Até 10 arquivos, 7 MB cada
Uma imagem durante os testes
System Instruction
Define o papel do modelo
Uma frase curta
Thinking Level
none, low ou high
none
Temperature
Aleatoriedade de 0 a 2
0,2 para OCR, 1 para legendas
Max Output Tokens
Limita o tamanho da resposta
O padrão serve
Os limites no PicassoIA são diferentes dos limites nativos da API acima, então trate a página como um laboratório de prompts e a API como o caminho de produção. Para uma segunda opinião sobre uma imagem difícil, rode o mesmo prompt pelo Gemini 3.1 Pro, pelo Qwen3.7-Plus, que interpreta imagens tão bem quanto texto, ou pelo Granite Vision 4.1 4B, feito para gráficos e tabelas.
Crie suas próprias imagens de teste
Você não precisa de uma pasta com fotos reais para começar. Gere uma mesa bagunçada, uma prateleira de mercado, uma rua chuvosa ou um recibo amassado com o PicassoIA Image ou o Seedream 4.5, depois envie cada resultado para o Gemini 3.5 Flash e veja o que ele consegue ler.
Faça três experimentos esta semana. Peça texto alternativo para cinco fotos geradas. Peça uma caixa delimitadora em volta de um objeto em uma cena movimentada. Peça um total em JSON a partir de uma imagem de recibo. Cada um leva minutos, e juntos mostram onde o modelo é preciso e onde o seu prompt precisa de ajustes.
Abra o PicassoIA, crie sua primeira imagem de teste e rode o seu próprio prompt. Veja todos os modelos disponíveis em picassoia.com/en/all-models e combine um gerador de imagens com um modelo de visão para montar o seu próprio fluxo de trabalho de imagem para texto.