Cadrer le problème
Transforme une idée de produit vague en une spécification de tâche de trois lignes, et garde la règle métier dans le code pour pouvoir la modifier sans réentraîner le modèle.

La plupart des projets de vision par ordinateur qui s’enlisent n’ont jamais eu de question clairement formulée. « Détecter les comportements dangereux » semble être une exigence, mais une personne chargée de l’annotation ne peut pas l’étiqueter, un modèle ne peut pas l’apprendre et personne ne peut dire si ça fonctionne. Une spécification de trois lignes règle le problème en un après-midi — et détermine quelle tâche entraîner, quoi annoter et quelle métrique rapporter.
Pratique
Pourquoi la spécification passe en premier#

Chaque étape d’un projet de vision par ordinateur hérite de son objectif de l’étape 0. Une question vague produit un jeu de données vague, des désaccords entre les annotateurs et une métrique qui mesure la mauvaise chose — et aucun entraînement à l’étape 2 ne peut corriger cela.
Les trois lignes#
Une spécification de tâche se compose de trois phrases, à raison d’une par ligne. Chacune répond à une question qu’une personne différente du projet posera :
| Ligne | Question à laquelle elle répond | Vague | Précise |
|---|---|---|---|
| Entrée | Que voit le modèle ? | « Images de caméra » | « Images de 1920×1080 à 5 fps provenant de 12 caméras au plafond » |
| Sortie | Quelles données sont renvoyées ? | « Détecter les problèmes de sécurité » | « Boîtes pour forklift et person, chacune accompagnée d’un score de confiance » |
| Décision | Qui agit, et quand ? | « Améliorer la sécurité » | « Avertir le responsable d’équipe lorsqu’un chariot élévateur et une personne se trouvent à moins de 2 m l’un de l’autre pendant 2 s » |
La ligne de sortie mérite le plus d’attention, car son type de données détermine la tâche :

Une étiquette pour l’image entière signifie classification ; des boîtes, détection ; des contours, segmentation ; des articulations, pose ; des boîtes orientées, OBB ; une classe ou une distance par pixel, segmentation sémantique ou profondeur. La leçon suivante présente les sept tâches.
Exemple détaillé : séparer le modèle de la règle#
« Nous voulons savoir quand les chariots élévateurs font quelque chose de dangereux dans l’entrepôt. »
Cette phrase décrit un projet, pas une tâche. Elle mêle deux fonctions : repérer les chariots élévateurs et les personnes, ce qui concerne les pixels, et décider de ce qui est dangereux, ce qui relève des règles. Sépare-les :
Seul le détecteur constitue le modèle. Le losange est du code ordinaire. Tu peux essayer cette séparation tout de suite : bus.jpg ne contient pas de chariot élévateur, mais un bus et quatre personnes permettent d’effectuer le même test. Une première règle indique : « déclencher une alerte lorsque plus de 30 % de la boîte d’une personne chevauche la boîte d’un véhicule » :
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
result = model("https://ultralytics.com/images/bus.jpg", verbose=False)[0]
# The model's job ends here: a class, a box, and a confidence per object.
people = [b.xyxy[0].tolist() for b in result.boxes if result.names[int(b.cls)] == "person"]
vehicles = [b.xyxy[0].tolist() for b in result.boxes if result.names[int(b.cls)] == "bus"]
def share_inside(a, b):
"""Fraction of box a's area that lies inside box b."""
w = max(0, min(a[2], b[2]) - max(a[0], b[0]))
h = max(0, min(a[3], b[3]) - max(a[1], b[1]))
return w * h / ((a[2] - a[0]) * (a[3] - a[1]))
# The decision rule is plain code: change the policy without retraining.
ALERT_SHARE = 0.30
for person in people:
share = max(share_inside(person, v) for v in vehicles)
print(f"person at x={person[0]:3.0f}: {share:4.0%} inside the bus box -> {'ALERT' if share > ALERT_SHARE else 'ok'}")person at x= 49: 70% inside the bus box -> ALERT
person at x=223: 76% inside the bus box -> ALERT
person at x=670: 70% inside the bus box -> ALERT
person at x= 0: 62% inside the bus box -> ALERTQuatre alertes, toutes fausses : les personnes sont sur le trottoir devant un bus garé. Le détecteur a raison pour chaque boîte ; c’est la règle qui est erronée, car un chevauchement dans une image 2D ne signifie pas que deux objets sont proches dans le monde réel. Puisque la règle est du code, la correction se fait dans le code. Compare l’endroit où les pieds de chaque personne touchent le sol à la ligne des roues du bus :
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
result = model("https://ultralytics.com/images/bus.jpg", verbose=False)[0]
people = [b.xyxy[0].tolist() for b in result.boxes if result.names[int(b.cls)] == "person"]
vehicles = [b.xyxy[0].tolist() for b in result.boxes if result.names[int(b.cls)] == "bus"]
def same_ground_line(person, vehicle, tolerance=40):
"""True when the person's feet are level with the vehicle's wheels and inside its width."""
feet_x, feet_y = (person[0] + person[2]) / 2, person[3]
return vehicle[0] < feet_x < vehicle[2] and abs(feet_y - vehicle[3]) < tolerance
for person in people:
alert = any(same_ground_line(person, v) for v in vehicles)
print(f"person at x={person[0]:3.0f}: feet y={person[3]:.0f}, bus wheels y={vehicles[0][3]:.0f} -> {'ALERT' if alert else 'ok'}")person at x= 49: feet y=902, bus wheels y=751 -> ok
person at x=223: feet y=861, bus wheels y=751 -> ok
person at x=670: feet y=880, bus wheels y=751 -> ok
person at x= 0: feet y=871, bus wheels y=751 -> okLes pieds de chaque personne se trouvent de 110 à 150 pixels sous la ligne des roues : elles sont donc plus proches de la caméra que le bus. Pas de réentraînement ni de nouvelle annotation : l’équipe de sécurité affine la règle tandis que le détecteur reste inchangé. Une version de production projetterait les pieds sur les coordonnées au sol à l’aide d’une caméra calibrée et ajouterait la persistance de 2 secondes grâce au suivi d’objets — toujours sous forme de code appliqué aux mêmes boîtes.
Les mots subjectifs — « dangereux », « défectueux », « suspect », « VIP » — ont leur place dans le code qui lit la sortie du modèle. Un modèle répond à des questions sur les pixels. Si deux experts se disputeraient au sujet d’une étiquette, le débat doit avoir lieu dans une règle que tu peux versionner, tester et modifier.
Pièges#
Symptôme : le cahier des charges dit « détecter les problèmes de sécurité » ou « comprendre la scène », et les annotateurs demandent quoi dessiner. Solution : reformule la sortie sous forme de type de données avec des classes nommées : « des boîtes pour forklift et person ».
Symptôme : une classe comme suspicious_behavior ou dangerous que deux annotateurs étiquettent différemment sur la même image. Solution : remplace-la par des éléments visibles — une personne dans une zone réglementée, une porte maintenue ouverte — et déplace le jugement dans la règle de décision.
Symptôme : « décrire ce qui se passe » (légendage) ou « prédire si le chariot élévateur va heurter quelqu’un » (prévision). Solution : localise d’abord les objets, puis ajoute le suivi et les règles de mouvement. Construis le détecteur avant de faire des prédictions.
De la spécification aux critères de réussite#
La spécification indique ce que fait le modèle, pas quel niveau de qualité est suffisant ni quel est le coût d’une omission par rapport à une fausse alerte. Commencer par l’objectif métier, dans Créer des jeux de données YOLO haute performance, transforme la spécification en objectifs mesurables. Chaque leçon suivante de ce cours renvoie à tes trois lignes.
Afficher la solution
Une spécification pour la caméra du rayon :
- Entrée : une image fixe de 1920×1080 toutes les 60 secondes, capturée par une caméra fixe qui filme une allée.
- Sortie : des boîtes englobantes pour
productetempty_facing(un emplacement de rayon sans produit), chacune accompagnée d’un score de confiance. - Décision : créer une tâche de réapprovisionnement lorsque trois boîtes
empty_facingou plus sur le même rayon persistent pendant cinq images fixes consécutives durant les heures d’ouverture du magasin.
Les expressions que le modèle ne peut pas voir sont tâche de réapprovisionnement, même rayon, persistent pendant cinq images fixes et heures d’ouverture du magasin. Sous forme de règle :
if count(empty_facing on shelf S) >= 3 in each of the last 5 stills and store_is_open(now):
create_restock_task(shelf=S)Le magasin peut modifier « 3 », « 5 » ou les heures d’ouverture sans réannoter une seule image.