Introduction
La Google Cloud Vision API est un service d'IA puissant pour analyser des images : détection d'objets, reconnaissance optique de caractères (OCR), analyse de visages avec landmarks émotionnels, et bien plus. En 2026, elle intègre les dernières avancées en vision par ordinateur, comme la détection contextuelle et le SAFE_SEARCH pour la modération de contenu.
Pourquoi l'utiliser ? Pour des applications comme l'analyse automatisée de documents, la surveillance vidéo intelligente ou l'e-commerce avec tagging automatique d'images. Ce tutoriel advanced cible les développeurs seniors : nous couvrons l'authentification service account, les features complexes (landmarks faciaux, localisation d'objets), le batch processing pour scaler, et les optimisations coûts/performance. À la fin, vous déployez une API Node.js robuste. Comptez 2000+ mots de concret, zéro fluff. Préparez votre compte Google Cloud et une clé JSON.
Prérequis
- Compte Google Cloud activé avec Vision API (facturation requise, ~1,50$/1000 images).
- Node.js 20+ et TypeScript.
- Clé de service account JSON (créez-en une via IAM > Service Accounts > Create Key > JSON).
- Une image test locale (ex:
test.jpgpour labels,document.pngpour OCR). - Connaissances avancées en async/await, streams et gestion d'erreurs Node.js.
Installation du projet
mkdir vision-api-project && cd vision-api-project
npm init -y
npm install @google-cloud/vision typescript ts-node @types/node
npm install -D nodemon
tsc --init --target es2022 --module commonjs --outDir ./dist --rootDir ./src --strict true
echo '{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}' > tsconfig.jsonCe script initialise un projet TypeScript propre avec @google-cloud/vision. ts-node permet d'exécuter directement les .ts ; nodemon pour le dev. Placez votre service-account-key.json à la racine. Lancez avec npx ts-node src/index.ts.
Authentification et client init
Téléchargez votre clé JSON depuis Google Cloud Console (IAM > Service Accounts). Activez la Vision API dans APIs & Services. Ne commitez jamais cette clé : utilisez .env ou secrets manager en prod. Le client ImageAnnotatorClient gère les appels REST sous le capot, avec retry automatique.
Détection de labels basique
import { ImageAnnotatorClient } from '@google-cloud/vision';
import * as fs from 'fs';
import * as path from 'path';
const keyPath = path.join(__dirname, '../service-account-key.json');
const client = new ImageAnnotatorClient({ keyFilename: keyPath });
const fileName = path.join(__dirname, '../test.jpg');
const request = {
image: { content: fs.readFileSync(fileName).toString('base64') },
features: [{ type: 'LABEL_DETECTION', maxResults: 10 }]
};
async function detectLabels() {
try {
const [result] = await client.annotateImage(request);
const labels = result.labelAnnotations;
console.log('Labels:', labels?.map(l => `${l.description} (${l.score})`).join('\n'));
} catch (error) {
console.error('Erreur:', error);
}
}
detectLabels();Ce script charge une image en base64, détecte 10 labels max avec scores de confiance. Analogie : comme un expert ornithologue identifiant oiseaux sur photo. Piège : oubliez toString('base64') et l'API rejette. Scores <0.8 souvent noisy.
OCR avancé multilingue
import { ImageAnnotatorClient } from '@google-cloud/vision';
import * as fs from 'fs';
import * as path from 'path';
const keyPath = path.join(__dirname, '../service-account-key.json');
const client = new ImageAnnotatorClient({ keyFilename: keyPath });
const fileName = path.join(__dirname, '../document.png');
const request = {
image: { content: fs.readFileSync(fileName).toString('base64') },
features: [
{ type: 'TEXT_DETECTION', maxResults: 1 },
{ type: 'DOCUMENT_TEXT_DETECTION', maxResults: 1 }
],
imageContext: {
languageHints: ['fr', 'en', 'es']
}
};
async function detectText() {
try {
const [result] = await client.annotateImage(request);
const texts = result.textAnnotations;
console.log('Texte principal:', texts?.[0]?.description);
texts?.slice(1).forEach((text, i) => {
console.log(`Bloc ${i + 1}:`, text.description);
});
} catch (error) {
console.error('Erreur OCR:', error);
}
}
detectText();Utilise DOCUMENT_TEXT_DETECTION pour docs structurés (vs TEXT_DETECTION pour texte simple). languageHints booste précision multilingue. Analogie : scanner haute-res comme un archiviste. Piège : images floues → forcez pré-processing (sharpening).
Analyse de visages avec landmarks
Face detection avancée extrait émotions (joy, sorrow), landmarks (yeux, nez) pour tracking. Utile en AR/VR ou sécurité. Combine avec SAFE_SEARCH_DETECTION pour modération.
Détection visages et landmarks
import { ImageAnnotatorClient } from '@google-cloud/vision';
import * as fs from 'fs';
import * as path from 'path';
type Landmark = { type: string; position: { x: number; y: number } };
const keyPath = path.join(__dirname, '../service-account-key.json');
const client = new ImageAnnotatorClient({ keyFilename: keyPath });
const fileName = path.join(__dirname, '../portrait.jpg');
const request = {
image: { content: fs.readFileSync(fileName).toString('base64') },
features: [
{ type: 'FACE_DETECTION', maxResults: 5 },
{ type: 'SAFE_SEARCH_DETECTION' }
]
};
async function detectFaces() {
try {
const [result] = await client.annotateImage(request);
const faces = result.faceAnnotations;
const safe = result.safeSearchAnnotation;
faces?.forEach((face, i) => {
console.log(`Visage ${i + 1}:`);
console.log('Joie:', face.joyLikelihood);
console.log('Landmarks:', face.landmarkAnnotations?.slice(0, 5).map((l: Landmark) => `${l.type}: (${l.position?.x?.toFixed(0)}, ${l.position?.y?.toFixed(0)})`));
});
console.log('SafeSearch:', safe);
} catch (error) {
console.error('Erreur faces:', error);
}
}
detectFaces();Extrait joyLikelihood (VERY_LIKELY, etc.) et 5 premiers landmarks (RIGHT_EYE, etc.). SAFE_SEARCH score ADULT/VIOLENCE. Analogie : profiler facial comme un détective. Piège : boundingPoly ignoré → perd localisation ; utilisez pour crop.
Localisation d'objets
import { ImageAnnotatorClient } from '@google-cloud/vision';
import * as fs from 'fs';
import * as path from 'path';
const keyPath = path.join(__dirname, '../service-account-key.json');
const client = new ImageAnnotatorClient({ keyFilename: keyPath });
const fileName = path.join(__dirname, '../scene.jpg');
const request = {
image: { content: fs.readFileSync(fileName).toString('base64') },
features: [{ type: 'OBJECT_LOCALIZATION', maxResults: 10 }],
imageContext: { pageSize: 2 }
};
async function localizeObjects() {
try {
const [result] = await client.annotateImage(request);
const objects = result.localizedObjectAnnotations;
objects?.forEach(obj => {
console.log(`Objet: ${obj.name} (score: ${obj.score})`);
const vertices = obj.boundingPoly?.normalizedVertices;
console.log('BBox:', vertices?.map(v => `(${v.x?.toFixed(2)}, ${v.y?.toFixed(2)})`));
});
} catch (error) {
console.error('Erreur objets:', error);
}
}
localizeObjects();OBJECT_LOCALIZATION donne bounding boxes normalisées (0-1). pageSize:2 pour pagination. Analogie : heatmap objets comme un radar. Piège : normalizedVertices pour scale-invariante ; dénormalisez avec largeur/hauteur image.
Batch processing multi-images
import { ImageAnnotatorClient } from '@google-cloud/vision';
import * as fs from 'fs';
import * as path from 'path';
const keyPath = path.join(__dirname, '../service-account-key.json');
const client = new ImageAnnotatorClient({ keyFilename: keyPath });
const images = ['test1.jpg', 'test2.jpg', 'test3.jpg'].map(name => path.join(__dirname, '../', name));
const requests = images.map(imagePath => ({
image: { content: fs.readFileSync(imagePath).toString('base64') },
features: [{ type: 'LABEL_DETECTION', maxResults: 5 }]
}));
async function batchAnnotate() {
try {
const [results] = await client.batchAnnotateImages({ requests });
results.forEach((result, i) => {
console.log(`Image ${i + 1}:`);
const labels = result.labelAnnotations;
console.log(labels?.map(l => l.description).join(', '));
});
} catch (error) {
console.error('Erreur batch:', error);
}
}
batchAnnotate();batchAnnotateImages traite jusqu'à 16 images en parallèle, économise quotas/coûts. Analogie : convoyeur d'analyse IA. Piège : erreur sur une image n'arrête pas le batch, mais loggez error dans fullTextAnnotation.
Bonnes pratiques
- Cachez résultats : labels/OCR stables → Redis avec TTL 24h, évitez appels redondants (coût ~1$/k images).
- Pré-traitez images : resize <4MP avec Sharp.js, booste vitesse/précision.
- Quotas & coûts : limitez
maxResults:5, monitor via Cloud Monitoring ; batch pour scale. - Streams pour gros fichiers : utilisez
source: { stream: fs.createReadStream() }vs base64. - TypeScript strict : étendez types pour
Landmarkcomme ci-dessus.
Erreurs courantes à éviter
- Auth invalide : 'Region mismatch' → clé EU/US ? Utilisez
projectIdexplicite dans client opts. - Base64 overflow : images >20MB crash → chunk ou GCS URI (
image: { source: { gcsImageUri: 'gs://bucket/img.jpg' } }). - Hints ignorés : OCR faible sans
languageHints; testezfr-FRvsfr. - Async non géré : toujours
try/catch+error.codepour retry (ex: RESOURCE_EXHAUSTED).
Pour aller plus loin
Approfondissez avec Vertex AI Vision pour modèles custom. Intégrez à Next.js App Router pour une API serverless. Ressources : Docs officielles Vision API, Codelab Google. Découvrez nos formations Learni sur Google Cloud IA pour certification pro.