📑 Table des matières

Vision IA : analyser des images avec les LLM

LLM & Modèles 🟡 Intermédiaire ⏱️ 13 min de lecture 📅 2026-02-24

Vision IA : analyser des images avec les LLM

Les LLM ne se contentent plus de lire du texte. Les modèles multimodaux comme Claude 3.5, GPT-4V et Gemini Pro Vision peuvent voir et comprendre les images. OCR, analyse de photos, QA visuelle, review de maquettes... les cas d'usage sont immenses.

Dans ce guide, on explore les modèles vision disponibles, leurs forces, et on code des exemples concrets avec les API.


👁️ Les modèles vision en 2025

Qu'est-ce qu'un LLM multimodal ?

Un LLM classique prend du texte en entrée et produit du texte en sortie. Un LLM multimodal accepte aussi des images (et parfois de l'audio ou de la vidéo) en entrée.

LLM classique :    Texte → Texte
LLM multimodal :   Texte + Image → Texte

Le modèle "voit" l'image grâce à un encodeur visuel (souvent un Vision Transformer, ViT) qui convertit l'image en tokens compréhensibles par le LLM.

Les modèles principaux

Modèle Éditeur Résolution max Points forts Prix (input)
Claude 3.5 Sonnet Anthropic 8000×8000 Analyse détaillée, raisonnement ~$3/M tokens
Claude 3.5 Haiku Anthropic 8000×8000 Rapide, bon rapport qualité/prix ~$0.80/M tokens
GPT-4o OpenAI 2048×2048 Polyvalent, OCR excellent ~$2.50/M tokens
GPT-4o-mini OpenAI 2048×2048 Budget-friendly, correct ~$0.15/M tokens
Gemini 2.0 Flash Google Très haute Contexte immense, rapide ~$0.10/M tokens
Gemini 1.5 Pro Google Très haute Vidéo native, 2M tokens ~$1.25/M tokens
Llama 3.2 Vision Meta 1120×1120 Open source, local Gratuit (self-hosted)

Comment choisir ?

Besoin d'OCR précis ? → GPT-4o ou Claude 3.5 Sonnet
Besoin d'analyse détaillée ? → Claude 3.5 Sonnet
Budget serré ? → GPT-4o-mini ou Gemini Flash
Données sensibles (local) ? → Llama 3.2 Vision
Analyse vidéo ? → Gemini 1.5 Pro
Volume élevé ? → Gemini Flash ou GPT-4o-mini

🔍 Cas d'usage concrets

1. OCR — Extraction de texte depuis des images

L'OCR (Optical Character Recognition) classique (Tesseract) est limité aux textes bien formatés. Les LLM vision comprennent le contexte : ils lisent un reçu, un tableau manuscrit, une capture d'écran avec mise en page complexe.

Exemple : extraire les données d'une facture

import anthropic
import base64

client = anthropic.Anthropic()

# Charger l'image
with open("facture.png", "rb") as f:
    image_data = base64.standard_b64encode(f.read()).decode("utf-8")

message = client.messages.create(
    model="claude-3-5-sonnet-20241022",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/png",
                        "data": image_data,
                    },
                },
                {
                    "type": "text",
                    "text": (
                        "Extrais toutes les informations de cette facture "
                        "au format JSON : numéro, date, fournisseur, "
                        "lignes (description, quantité, prix unitaire, total), "
                        "total HT, TVA, total TTC."
                    )
                }
            ],
        }
    ],
)

print(message.content[0].text)

Résultat typique :

{
  "numero_facture": "FA-2025-0142",
  "date": "2025-01-15",
  "fournisseur": "TechServ SARL",
  "lignes": [
    {
      "description": "Hébergement VPS Standard",
      "quantite": 1,
      "prix_unitaire": 29.99,
      "total": 29.99
    },
    {
      "description": "Nom de domaine .fr",
      "quantite": 1,
      "prix_unitaire": 12.00,
      "total": 12.00
    }
  ],
  "total_ht": 41.99,
  "tva": 8.40,
  "total_ttc": 50.39
}

Comparaison OCR classique vs LLM vision :

Critère Tesseract (OCR) LLM Vision
Texte imprimé simple ✅ Excellent ✅ Excellent
Texte manuscrit ❌ Médiocre ✅ Bon
Tableaux complexes ❌ Échoue souvent ✅ Comprend la structure
Contexte sémantique ❌ Aucun ✅ Comprend le sens
Multilingue ⚡ Avec config ✅ Natif
Coût Gratuit Payant (API)
Vitesse ⚡ Très rapide 🐢 Plus lent

2. Analyse de photos — Comprendre le contenu visuel

Les LLM vision ne font pas que lire du texte. Ils comprennent ce qu'ils voient : objets, personnes, scènes, émotions, style.

Exemple : analyser une photo produit

from openai import OpenAI

client = OpenAI()

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": (
                        "Analyse cette photo produit pour un site e-commerce. "
                        "Donne-moi :\n"
                        "1. Description courte (1 phrase)\n"
                        "2. Description longue (SEO, 100 mots)\n"
                        "3. Tags (5-10 mots-clés)\n"
                        "4. Couleurs dominantes\n"
                        "5. Suggestions d'amélioration de la photo"
                    )
                },
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://example.com/product.jpg",
                        "detail": "high"  # high, low, ou auto
                    }
                }
            ],
        }
    ],
    max_tokens=500
)

print(response.choices[0].message.content)

3. Review de maquettes et interfaces

Un cas d'usage puissant : faire relire une maquette UI/UX par un LLM vision.

import anthropic
import base64

client = anthropic.Anthropic()

with open("maquette.png", "rb") as f:
    img = base64.standard_b64encode(f.read()).decode("utf-8")

message = client.messages.create(
    model="claude-3-5-sonnet-20241022",
    max_tokens=2048,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/png",
                        "data": img,
                    },
                },
                {
                    "type": "text",
                    "text": """Analyse cette maquette d'interface web.

Évalue sur 10 :
1. Hiérarchie visuelle
2. Lisibilité
3. Cohérence des espacements
4. Accessibilité (contraste, taille des textes)
5. Responsive-readiness

Pour chaque point < 8/10, propose une amélioration concrète.
Identifie aussi tout problème UX potentiel."""
                }
            ],
        }
    ],
)

print(message.content[0].text)

Résultat typique :

## 🎨 Analyse UX de la maquette

### 1. Hiérarchie visuelle : 7/10
Le titre principal est bien visible, mais les CTA secondaires
ont le même poids visuel que le CTA principal.
→ **Suggestion** : réduire la taille des boutons secondaires,
  augmenter le contraste du bouton principal.

### 2. Lisibilité : 8/10
Bonne taille de police, interligne correct.
Léger manque de contraste sur le texte gris clair (#999) sur fond blanc.
→ **Suggestion** : passer le gris à #666 minimum (ratio 4.5:1).

### 3. Cohérence des espacements : 6/10
Les marges entre les sections varient (32px, 24px, 40px).
→ **Suggestion** : standardiser à 32px ou utiliser un système
  de spacing (8px grid).
...

4. QA visuelle — Détection de bugs d'interface

Comparez une maquette et un screenshot de l'implémentation :

import anthropic
import base64

client = anthropic.Anthropic()

def load_image(path):
    with open(path, "rb") as f:
        return base64.standard_b64encode(f.read()).decode("utf-8")

maquette = load_image("design_figma.png")
implementation = load_image("screenshot_prod.png")

message = client.messages.create(
    model="claude-3-5-sonnet-20241022",
    max_tokens=2048,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "Image 1 : la maquette Figma (référence)"
                },
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/png",
                        "data": maquette,
                    },
                },
                {
                    "type": "text",
                    "text": "Image 2 : le screenshot de l'implémentation"
                },
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/png",
                        "data": implementation,
                    },
                },
                {
                    "type": "text",
                    "text": """Compare la maquette (image 1) et l'implémentation (image 2).

Liste TOUTES les différences visuelles :
- Couleurs différentes
- Espacements incorrects
- Éléments manquants ou en trop
- Polices différentes
- Alignements décalés
- Tailles différentes

Format : tableau avec colonnes Élément | Maquette | Implémentation | Sévérité (haute/moyenne/basse)"""
                }
            ],
        }
    ],
)

print(message.content[0].text)

5. Accessibilité — Audit automatique d'images web

Vérifiez que vos images web sont accessibles (alt text pertinent, contraste suffisant) :

import anthropic
import base64

client = anthropic.Anthropic()

def audit_accessibility(image_path: str, current_alt: str) -> dict:
    """Audite une image pour l'accessibilité web."""
    with open(image_path, "rb") as f:
        img_data = base64.standard_b64encode(f.read()).decode("utf-8")

    message = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=1024,
        messages=[{
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/png",
                        "data": img_data,
                    },
                },
                {
                    "type": "text",
                    "text": f"""Audit d'accessibilité pour cette image.

Alt text actuel : "{current_alt}"

Retourne un JSON :
{{
    "alt_text_quality": "bon|moyen|mauvais",
    "suggested_alt": "texte alternatif optimal",
    "decorative": true/false,
    "text_in_image": true/false,
    "contrast_issues": "description ou null",
    "recommendations": ["liste", "de", "recommandations"]
}}

Un bon alt text est concis, descriptif, et transmet l'information
essentielle de l'image. Si l'image est purement décorative,
decorative=true et alt="" est acceptable."""
                }
            ],
        }],
    )

    import json
    return json.loads(message.content[0].text)

# Exemple
result = audit_accessibility("hero-banner.png", "image")
print(result)
# {
#   "alt_text_quality": "mauvais",
#   "suggested_alt": "Dashboard analytics montrant la croissance du trafic web sur 6 mois",
#   "decorative": false,
#   "text_in_image": true,
#   "contrast_issues": "Le texte blanc sur fond clair en bas à droite a un contraste insuffisant",
#   "recommendations": [
#     "Remplacer l'alt text 'image' par une description significative",
#     "Améliorer le contraste du texte incrusté",
#     "Fournir les données du graphique dans un tableau HTML accessible"
#   ]
# }

6. Classification et tri automatique de photos

Organisez automatiquement des milliers de photos par catégorie :

import anthropic
import base64
import shutil
from pathlib import Path

client = anthropic.Anthropic()

CATEGORIES = [
    "paysage", "portrait", "nourriture", "animal",
    "architecture", "document", "screenshot", "produit", "autre"
]

def classify_image(image_path: str) -> str:
    """Classifie une image dans une catégorie."""
    with open(image_path, "rb") as f:
        img_data = base64.standard_b64encode(f.read()).decode("utf-8")

    ext = Path(image_path).suffix.lower()
    media_type = "image/jpeg" if ext in [".jpg", ".jpeg"] else "image/png"

    message = client.messages.create(
        model="claude-3-5-haiku-20241022",  # Haiku suffit pour la classification
        max_tokens=50,
        messages=[{
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": media_type,
                        "data": img_data,
                    },
                },
                {
                    "type": "text",
                    "text": f"Classifie cette image. Réponds avec UN SEUL mot parmi : {', '.join(CATEGORIES)}"
                }
            ],
        }],
    )

    category = message.content[0].text.strip().lower()
    return category if category in CATEGORIES else "autre"

def organize_photos(source_dir: str, dest_dir: str):
    """Trie automatiquement les photos par catégorie."""
    source = Path(source_dir)
    dest = Path(dest_dir)

    extensions = {".jpg", ".jpeg", ".png", ".webp"}
    images = [f for f in source.iterdir() if f.suffix.lower() in extensions]

    print(f"📸 {len(images)} images à classifier...")

    stats = {}
    for i, img in enumerate(images):
        category = classify_image(str(img))

        # Créer le dossier de destination
        cat_dir = dest / category
        cat_dir.mkdir(parents=True, exist_ok=True)

        # Copier l'image
        shutil.copy2(img, cat_dir / img.name)

        stats[category] = stats.get(category, 0) + 1
        print(f"  [{i+1}/{len(images)}] {img.name}{category}")

    print(f"\n✅ Classification terminée !")
    for cat, count in sorted(stats.items(), key=lambda x: -x[1]):
        print(f"  {cat}: {count} images")

# Utilisation
organize_photos("./photos_vrac/", "./photos_triees/")

7. Extraction de données depuis des graphiques

Les LLM vision peuvent lire des graphiques et en extraire les données sous-jacentes :

import anthropic
import base64

client = anthropic.Anthropic()

def extract_chart_data(image_path: str) -> dict:
    """Extrait les données d'un graphique en image."""
    with open(image_path, "rb") as f:
        img_data = base64.standard_b64encode(f.read()).decode("utf-8")

    message = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=2048,
        messages=[{
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/png",
                        "data": img_data,
                    },
                },
                {
                    "type": "text",
                    "text": """Extrais les données de ce graphique.

Retourne un JSON structuré avec :
- "chart_type": type de graphique (bar, line, pie, scatter, etc.)
- "title": titre du graphique s'il est visible
- "x_axis": label de l'axe X
- "y_axis": label de l'axe Y
- "data": les données extraites sous forme de tableau
- "insights": 2-3 observations clés

Pour aller plus loin sur ce sujet, consultez notre guide [Claude, GPT, Gemini, Llama : quel modèle choisir en 2026 ?](/article/comparatif-llm-2026-claude-gpt-gemini-llama).

Sois aussi précis que possible sur les valeurs."""
                }
            ],
        }],
    )

    import json
    return json.loads(message.content[0].text)

Pour aller plus loin sur ce sujet, consultez notre guide [Utiliser des modèles gratuits sans sacrifier la qualité](/article/modeles-ia-gratuits-openrouter-groq).

# Exemple avec un graphique de ventes
result = extract_chart_data("sales_chart_q4.png")
# {
#   "chart_type": "bar",
#   "title": "Ventes mensuelles Q4 2025",
#   "x_axis": "Mois",
#   "y_axis": "Chiffre d'affaires (K€)",
#   "data": [
#     {"mois": "Octobre", "valeur": 145},
#     {"mois": "Novembre", "valeur": 178},
#     {"mois": "Décembre", "valeur": 210}
#   ],
#   "insights": [
#     "Croissance continue sur le trimestre (+45%)",
#     "Décembre est le mois le plus fort (effet fêtes)",
#     "La tendance suggère un Q1 2026 > 150K€/mois"
#   ]
# }

8. Surveillance visuelle et détection d'anomalies

Combinez la vision IA avec une caméra ou des captures d'écran pour détecter des changements :

import anthropic
import base64

client = anthropic.Anthropic()

def detect_visual_changes(
    before_path: str,
    after_path: str,
    context: str = "page web"
) -> dict:
    """Compare deux images et détecte les changements."""

    def load(path):
        with open(path, "rb") as f:
            return base64.standard_b64encode(f.read()).decode("utf-8")

    before = load(before_path)
    after = load(after_path)

    message = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=1024,
        messages=[{
            "role": "user",
            "content": [
                {"type": "text", "text": f"Image AVANT ({context}) :"},
                {
                    "type": "image",
                    "source": {"type": "base64", "media_type": "image/png", "data": before},
                },
                {"type": "text", "text": f"Image APRÈS ({context}) :"},
                {
                    "type": "image",
                    "source": {"type": "base64", "media_type": "image/png", "data": after},
                },
                {
                    "type": "text",
                    "text": """Compare ces deux images. Retourne un JSON :
{
    "has_changes": true/false,
    "severity": "none|low|medium|high|critical",
    "changes": [
        {"description": "...", "location": "...", "type": "ajout|suppression|modification"}
    ],
    "summary": "résumé en 1 phrase"
}"""
                }
            ],
        }],
    )

    import json
    return json.loads(message.content[0].text)

# Monitoring visuel d'un site web
result = detect_visual_changes(
    "screenshot_before.png",
    "screenshot_after.png",
    context="page d'accueil du site e-commerce"
)
if result["severity"] in ["high", "critical"]:
    send_alert(f"🚨 Changement visuel critique détecté : {result['summary']}")

💻 Utiliser la vision avec les API

API Anthropic (Claude)

import anthropic
import base64
import httpx

client = anthropic.Anthropic()

# Méthode 1 : Image en base64
with open("image.png", "rb") as f:
    image_base64 = base64.standard_b64encode(f.read()).decode("utf-8")

# Méthode 2 : Image depuis URL
image_url = "https://example.com/image.jpg"
image_data = base64.standard_b64encode(
    httpx.get(image_url).content
).decode("utf-8")

message = client.messages.create(
    model="claude-3-5-sonnet-20241022",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/jpeg",
                        "data": image_data,
                    },
                },
                {
                    "type": "text",
                    "text": "Décris cette image en détail."
                }
            ],
        }
    ],
)

Formats supportés par Claude : JPEG, PNG, GIF, WebP
Taille max : 20 MB par image, jusqu'à 100 images par requête

API OpenAI (GPT-4V / GPT-4o)

from openai import OpenAI

client = OpenAI()

# Méthode 1 : URL directe
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Que vois-tu ?"},
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://example.com/image.jpg",
                        "detail": "high"  # low, high, auto
                    }
                },
            ],
        }
    ],
    max_tokens=300,
)

# Méthode 2 : Base64
import base64

with open("image.png", "rb") as f:
    b64 = base64.b64encode(f.read()).decode()

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Analyse cette image."},
                {
                    "type": "image_url",
                    "image_url": {
                        "url": f"data:image/png;base64,{b64}"
                    }
                },
            ],
        }
    ],
)

Le paramètre detail chez OpenAI :

Valeur Tokens consommés Usage
low ~85 tokens fixe Aperçu rapide, classification
high ~85 + 170×tuiles Analyse détaillée, OCR
auto Choisi par le modèle Par défaut

API Google (Gemini)

import google.generativeai as genai
from PIL import Image

genai.configure(api_key="...")

model = genai.GenerativeModel("gemini-2.0-flash")

# Depuis un fichier
img = Image.open("image.jpg")
response = model.generate_content(
    ["Décris cette image en détail.", img]
)
print(response.text)

# Depuis une URL
import requests
from io import BytesIO

url = "https://example.com/image.jpg"
img = Image.open(BytesIO(requests.get(url).content))
response = model.generate_content(
    ["Que contient cette image ?", img]
)

Avantage Gemini : contexte de 2M tokens, peut analyser des vidéos entières frame par frame.

Via OpenRouter (tous les modèles)

Si vous utilisez OpenRouter, vous accédez à tous ces modèles via une API unique :

from openai import OpenAI

client = OpenAI(
    base_url="https://openrouter.ai/api/v1",
    api_key="sk-or-..."
)

# Même format OpenAI, n'importe quel modèle
response = client.chat.completions.create(
    model="anthropic/claude-3.5-sonnet",  # ou google/gemini-2.0-flash
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Analyse cette image."},
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://example.com/image.jpg"
                    }
                },
            ],
        }
    ],
)

⚡ Optimiser les performances et les coûts

Réduire la taille des images

Les images haute résolution consomment beaucoup de tokens. Redimensionnez avant d'envoyer :

from PIL import Image
import io
import base64

def optimize_image(
    path: str,
    max_size: int = 1024,
    quality: int = 85
) -> str:
    """Optimise une image avant envoi à l'API"""
    img = Image.open(path)

    # Redimensionner si nécessaire
    if max(img.size) > max_size:
        ratio = max_size / max(img.size)
        new_size = (
            int(img.size[0] * ratio),
            int(img.size[1] * ratio)
        )
        img = img.resize(new_size, Image.LANCZOS)

    # Convertir en JPEG (plus léger que PNG)
    buffer = io.BytesIO()
    img.convert("RGB").save(buffer, format="JPEG", quality=quality)

    return base64.standard_b64encode(
        buffer.getvalue()
    ).decode("utf-8")

Calcul des coûts vision

Claude (Anthropic) :
Les images sont facturées en tokens selon leur taille :

Tokens ≈ (width × height) / 750

Exemples :
- 100×100 = ~54 tokens
- 1000×1000 = ~1334 tokens  
- 4000×4000 = ~21334 tokens

GPT-4o (OpenAI) :

Mode low : 85 tokens (fixe)
Mode high : 85 + 170 × nombre_de_tuiles_512x512

Exemples (high) :
- 512×512 = 85 + 170 = 255 tokens
- 1024×1024 = 85 + 170×4 = 765 tokens
- 2048×2048 = 85 + 170×16 = 2805 tokens

Stratégie multi-modèles

def analyze_image(image_path: str, task: str) -> str:
    """Choisit le bon modèle selon la tâche"""

    if task == "classification":
        # Tâche simple → modèle bon marché
        return call_api("gpt-4o-mini", image_path, detail="low")

    elif task == "ocr":
        # OCR précis → modèle performant
        return call_api("gpt-4o", image_path, detail="high")

    elif task == "analysis":
        # Analyse détaillée → meilleur modèle
        return call_api("claude-3-5-sonnet", image_path)

    elif task == "batch":
        # Traitement en masse → le moins cher
        return call_api("gemini-2.0-flash", image_path)
Tâche Modèle recommandé Coût estimé/image
Classification simple GPT-4o-mini (low) ~$0.001
OCR document GPT-4o (high) ~$0.01
Analyse détaillée Claude 3.5 Sonnet ~$0.02
Batch processing Gemini Flash ~$0.001
QA visuelle (2 images) Claude 3.5 Sonnet ~$0.04

🛠️ Projet pratique : analyseur d'images automatique

Voici un script complet qui analyse un dossier d'images et génère un rapport :

"""
Analyseur d'images automatique
Utilise Claude 3.5 Sonnet pour analyser un dossier d'images
"""

import anthropic
import base64
import json
import os
from pathlib import Path

client = anthropic.Anthropic()

def encode_image(path: str) -> tuple[str, str]:
    """Encode une image en base64 et détecte le type"""
    ext = Path(path).suffix.lower()
    media_types = {
        ".jpg": "image/jpeg",
        ".jpeg": "image/jpeg",
        ".png": "image/png",
        ".gif": "image/gif",
        ".webp": "image/webp",
    }
    media_type = media_types.get(ext, "image/jpeg")

    with open(path, "rb") as f:
        data = base64.standard_b64encode(f.read()).decode("utf-8")

    return data, media_type

def analyze_image(path: str) -> dict:
    """Analyse une image avec Claude Vision"""
    data, media_type = encode_image(path)

    message = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=1024,
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": media_type,
                            "data": data,
                        },
                    },
                    {
                        "type": "text",
                        "text": """Analyse cette image et retourne un JSON :
{
    "description": "description courte en 1 phrase",
    "category": "photo|screenshot|document|illustration|other",
    "objects": ["liste", "des", "objets", "détectés"],
    "text_content": "texte visible dans l'image ou null",
    "colors": ["couleurs", "dominantes"],
    "mood": "ambiance générale",
    "quality_score": 8,
    "suggestions": "améliorations possibles"
}
Retourne UNIQUEMENT le JSON, pas de texte autour."""
                    }
                ],
            }
        ],
    )

    try:
        return json.loads(message.content[0].text)
    except json.JSONDecodeError:
        return {"raw": message.content[0].text}

def analyze_folder(folder: str) -> list[dict]:
    """Analyse toutes les images d'un dossier"""
    results = []
    extensions = {".jpg", ".jpeg", ".png", ".gif", ".webp"}

    for file in sorted(Path(folder).iterdir()):
        if file.suffix.lower() in extensions:
            print(f"Analyse de {file.name}...")
            result = analyze_image(str(file))
            result["filename"] = file.name
            results.append(result)
            print(f"  → {result.get('description', 'OK')}")

    return results

if __name__ == "__main__":
    import sys

    folder = sys.argv[1] if len(sys.argv) > 1 else "."
    results = analyze_folder(folder)

    # Sauvegarder le rapport
    with open("rapport_images.json", "w") as f:
        json.dump(results, f, indent=2, ensure_ascii=False)

    print(f"\n{len(results)} images analysées")
    print("Rapport sauvegardé dans rapport_images.json")
$ python analyze_folder.py ./photos/

Analyse de photo_001.jpg...
   Bureau moderne avec écran affichant du code Python
Analyse de photo_002.png...
   Capture d'écran d'un dashboard analytics avec graphiques
Analyse de facture.png...
   Facture TechServ SARL datée du 15 janvier 2025 3 images analysées
Rapport sauvegardé dans rapport_images.json

🔮 L'avenir de la vision IA

Tendances 2025-2026

  • Vidéo native : Gemini analyse déjà des vidéos, les autres suivront
  • Vision en temps réel : analyse de flux caméra avec latence < 1s
  • Génération + compréhension : les modèles qui voient ET créent des images
  • Agents visuels : des agents qui naviguent des interfaces en "regardant" l'écran
  • Coûts en chute libre : la vision deviendra quasi-gratuite d'ici fin 2025

Vision + Agents IA

La combinaison la plus puissante : un agent IA qui voit son environnement. OpenClaw utilise déjà la vision pour :

  • Analyser des captures d'écran (browser automation)
  • Lire des images envoyées par l'utilisateur
  • Vérifier visuellement des résultats (QA)

C'est la prochaine frontière de l'IA autonome : des agents qui comprennent le monde visuel aussi bien que le texte.


📚 Articles liés