Automatiser l’OCR d’images avec GCP Vision et Python
Transformez une page numérisée ou une capture d’écran en texte avec un petit programme Python en ligne de commande. Cet exemple envoie une image JPEG ou PNG locale à Google Cloud Vision et affiche le texte reconnu, ou un résumé JSON qu’un autre programme peut exploiter. Il ne nécessite aucun bucket Cloud Storage.
Prérequis
- Python 3.14.7 ou une version de maintenance plus récente de Python 3.14, à installer depuis la page de téléchargement de Python.
- La Google Cloud CLI et un projet Google Cloud pour lequel la facturation et l’API Cloud Vision sont activées.
- Une image JPEG ou PNG locale que vous êtes autorisé à envoyer à Google Cloud.
Les commandes ci-dessous utilisent Bash sur macOS. Ce tutoriel a été testé avec Python 3.14.7 et
google-cloud-vision 3.16.0. Ouvrez un terminal dans un répertoire dédié à cet exemple et
conservez-y le programme et votre image. Vérifiez que les outils requis fonctionnent avant de créer
l’environnement virtuel :
python3.14 --version && gcloud --version
Configurer le projet cloud
Dans la Google Cloud Console, sélectionnez un projet, vérifiez que la facturation est activée et activez l’API Cloud Vision. Notez l’identifiant du projet. Si une autre personne gère le projet, demandez-lui d’effectuer ces opérations et d’autoriser votre compte à y accéder. Consultez le guide de configuration de Vision de Google.
Configuration pour le développement
Pour le développement local, utilisez Application Default Credentials (ADC). Remplacez
PROJECT_ID ci-dessous par l’identifiant de votre projet, puis connectez-vous avec
un compte autorisé à utiliser ce projet :
gcloud auth application-default login &&
gcloud auth application-default set-quota-project PROJECT_ID
Les données d’authentification ADC sont distinctes de celles de la connexion habituelle à la CLI.
La commande définissant le projet de quota nécessite serviceusage.services.use, fourni par le
rôle Service Usage Consumer. Un paramètre GOOGLE_APPLICATION_CREDENTIALS déjà défini est prioritaire
sur le fichier ADC local. Vérifiez qu’il pointe vers les données d’authentification prévues, ou
supprimez cette configuration prioritaire de ce terminal avant d’utiliser la connexion locale.
Le guide d’authentification de Google explique les exigences de
connexion et de configuration du projet de quota. Ne placez pas de données d’authentification dans
le programme.
Authentification en production
Pour un éventuel déploiement, privilégiez un compte de service associé sur Google Cloud ou Workload Identity Federation ailleurs. Les deux fonctionnent avec ADC sans télécharger de clé de compte de service. Ce tutoriel utilise les données d’authentification d’un utilisateur local et ne configure pas de déploiement en production.
Installer le client Python
Créez un nouvel environnement virtuel et installez le client à la version fixée. Appeler directement son interpréteur évite l’activation dans le shell et maintient l’installation dans ce répertoire :
test ! -e .venv && test ! -L .venv &&
python3.14 -m venv .venv &&
./.venv/bin/python -m pip install 'google-cloud-vision==3.16.0'
La première vérification refuse de réutiliser un .venv existant. Si
l’installation échoue après la création de l’environnement, conservez vos fichiers et relancez
uniquement la commande d’installation :
./.venv/bin/python -m pip install 'google-cloud-vision==3.16.0'
Si la création de l’environnement virtuel elle-même a échoué, choisissez un nouveau répertoire pour
l’exemple avant de recommencer la configuration. Utilisez l’interpréteur
.venv pour les commandes suivantes, même si un autre environnement est actif
dans votre terminal.
Enregistrer le programme OCR
Enregistrez le bloc complet sous le nom extract_text.py. Il utilise
document_text_detection pour le texte dense des pages et lit full_text_annotation.text,
comme décrit dans le tutoriel de détection du texte de documents
de Google. Le transport REST utilise toujours le client Python officiel et ADC.
import argparse
import json
from pathlib import Path
import sys
import time
from google.api_core.exceptions import ServiceUnavailable
from google.cloud import vision
class OcrError(RuntimeError):
"""A safe diagnostic generated by this program."""
def process_ocr_text(raw_text: str) -> dict:
lines = raw_text.splitlines()
return {
'full_text': raw_text,
'lines': lines,
'line_count': len(lines),
'word_count': len(raw_text.split()),
'cleaned_text': ' '.join(raw_text.split()),
}
def safe_ocr_call(client, image):
for attempt in range(3):
try:
response = client.document_text_detection(
image=image, retry=None, timeout=30.0
)
except ServiceUnavailable:
if attempt == 2:
raise
time.sleep(2 ** attempt)
continue
if response.error.code:
raise OcrError(f'Vision OCR failed (code {response.error.code}).')
return response
def extract_text(image_path: str) -> str:
path = Path(image_path)
if path.suffix.lower() not in ('.jpg', '.jpeg', '.png'):
raise OcrError('Use one JPEG or PNG image, not a PDF or TIFF.')
content = path.read_bytes()
if not content.startswith((b'\x89PNG\r\n\x1a\n', b'\xff\xd8\xff')):
raise OcrError('Input does not have a JPEG or PNG signature.')
with vision.ImageAnnotatorClient(transport='rest') as client:
response = safe_ocr_call(client, vision.Image(content=content))
return response.full_text_annotation.text
def main() -> int:
parser = argparse.ArgumentParser(description='Extract text from one JPEG or PNG.')
parser.add_argument('image_path')
parser.add_argument('--json', action='store_true', help='Print a JSON summary.')
args = parser.parse_args()
try:
text = extract_text(args.image_path)
except OcrError as error:
print(error, file=sys.stderr)
return 1
except Exception as error:
print(f'OCR failed ({type(error).__name__}).', file=sys.stderr)
return 1
if args.json:
print(json.dumps(process_ocr_text(text), ensure_ascii=False))
else:
sys.stdout.write(text)
if not text:
print('No text detected.', file=sys.stderr)
return 0
if __name__ == '__main__':
sys.exit(main())
La vérification de la signature détecte les fichiers vides et les erreurs de format évidentes avant l’envoi d’une requête. Elle ne décode ni ne valide entièrement l’image. Si l’image présente des dommages au-delà de l’en-tête, Vision peut la rejeter ou la récupérer. Examinez l’image source et comparez-la au texte reconnu avant d’utiliser le résultat.
Exécuter le programme sur votre image
Enregistrez une numérisation ou une capture d’écran nette sous le nom
invoice.png à côté du programme, puis exécutez :
./.venv/bin/python extract_text.py invoice.png
Le texte reconnu est envoyé sur la sortie standard avec ses sauts de ligne d’origine. Une requête
réussie sans texte reconnu se termine avec le code zéro, laisse la sortie standard vide et affiche
No text detected. sur la sortie d’erreur standard. Il s’agit d’un résultat de
reconnaissance, et non d’une preuve que l’image ne contient aucune écriture. En cas d’erreur, le
programme se termine avec le code un et sans texte extrait. Des arguments de ligne de commande
incorrects entraînent une sortie avec le code deux.
Pour obtenir l’exemple de normalisation associé, exécutez le même programme avec
--json :
./.venv/bin/python extract_text.py --json invoice.png
full_text conserve la réponse OCR. lines,
line_count et word_count décrivent ce texte.
cleaned_text réduit les séquences d’espaces pour faciliter la recherche. Ces champs
n’identifient ni les totaux des factures, ni les tableaux, ni les paragraphes du document. Un résultat
vide produit des chaînes vides, un tableau lines vide et des compteurs à zéro.
Diagnostiquer un échec d’extraction
Le programme désactive les nouvelles tentatives automatiques du client et effectue au maximum trois
appels à la méthode OCR. Il ne réessaie qu’en cas de ServiceUnavailable, avec des attentes
d’une et de deux secondes. Chaque appel a un délai d’expiration de 30 secondes pour la requête. Ce
délai ne s’applique pas à l’ensemble de la commande, qui comprend l’authentification et les attentes
entre les tentatives. Les échecs liés aux autorisations, l’épuisement des quotas et les erreurs
intégrées à la réponse pour chaque image ne déclenchent aucune nouvelle tentative.
FileNotFoundError: vérifiez le nom du fichier image et le répertoire courant de votre terminal.DefaultCredentialsError: terminez la connexion ADC ou corrigez une configuration prioritaire non souhaitée des données d’authentification.Forbidden,PermissionDeniedou le code intégré 7 : vérifiez l’accès au projet, l’activation de l’API et le projet de quota ADC. Répéter la même requête ne peut pas accorder d’autorisation.TooManyRequests,ResourceExhaustedou le code intégré 8 : examinez les quotas du projet avant de réessayer manuellement.- Le code intégré 3 ou
InvalidArgument: vérifiez que le fichier d’entrée est un JPEG ou un PNG lisible et intact.
Les messages d’erreur de tiers ne sont pas affichés, car ils peuvent contenir des détails de la requête. Les codes numériques intégrés et les noms d’exceptions indiquent la prochaine vérification à effectuer sans exposer ces détails.
Respecter les limites du flux de traitement des images
Ce programme lit une image complète en mémoire et l’envoie à un service cloud. Utilisez d’abord une petite image de test, vérifiez les formats pris en charge et les limites de taille et consultez les tarifs de Vision avant de traiter un volume plus important. Le traitement par lots peut réduire le surcoût des requêtes, mais ne supprime pas les frais par image liés aux fonctionnalités utilisées.
Pour les PDF ou TIFF de plusieurs pages, utilisez les API d’annotation de fichiers plutôt que de renommer le fichier ou de le transmettre à cette CLI dédiée aux images. La détection automatique de la langue et l’OCR peuvent tout de même mal interpréter le texte. Évaluez vos propres numérisations, systèmes d’écriture et mises en page. Un exemple synthétique net ne démontre pas la précision sur des reçus, du texte manuscrit ou des documents de production.
