Skip to content
Tutoriels8 min de lecture

Dessiner des boîtes englobantes pour la détection d'objets

Créez une tâche de détection d'objets dans Potato, d'une configuration de départ à trois étiquettes jusqu'à une configuration de production pour des vidéos de conduite, puis exportez en COCO ou YOLO.

Potato Team

Ce tutoriel construit une tâche d'annotation pour la détection d'objets dans Potato, d'une configuration à trois étiquettes jusqu'à l'export COCO ou YOLO sur lequel s'entraîne un détecteur. Pour la liste complète des outils d'image et de leurs options, consultez la documentation sur l'annotation d'images.

Le fichier de données

Chaque ligne du fichier de données correspond à une image. Potato a besoin d'un identifiant et d'un champ contenant l'URL ou le chemin de l'image, et item_properties indique quel champ joue quel rôle :

json
{"id": "img_001", "image_url": "https://example.com/street_001.jpg"}
{"id": "img_002", "image_url": "/static/images/street_002.jpg"}

Un chemin relatif est résolu par rapport à media_directory, donc les images locales n'exigent pas de serveur de fichiers en cours d'exécution.

Une configuration minimale

Le schéma image_annotation gère la surface de dessin. Il lui faut un nom, une description que les annotateurs lisent comme consigne, les outils à activer et l'ensemble d'étiquettes :

yaml
annotation_task_name: "Object Detection Annotation"
task_dir: "."
output_annotation_dir: "annotation_output/"
 
data_files:
  - "data/images.json"
 
item_properties:
  id_key: id
  text_key: image_url
 
annotation_schemes:
  - annotation_type: image_annotation
    name: objects
    description: "Draw a box around every car, person, and bicycle"
    tools:
      - bbox
    labels:
      - name: car
        color: "#FF6B6B"
      - name: person
        color: "#4ECDC4"
      - name: bicycle
        color: "#45B7D1"

Trois étiquettes, c'est un point de départ délibéré. Chaque étiquette ajoutée est une décision que l'annotateur doit prendre pour chaque objet, et un cas limite dont il faut lui expliquer la résolution. Commencez donc par les classes dont le modèle a réellement besoin et ajoutez les autres une fois que les consignes tiennent.

Lancez le serveur et ouvrez la tâche :

bash
potato start config.yaml -p 8000

Ce que fait l'annotateur

L'annotateur choisit une étiquette, puis trace un rectangle autour de chaque objet en ajustant les coins jusqu'à ce que la boîte soit bien serrée :

Interface d'annotation par boîtes englobantes pour la détection d'objetsL'outil de boîtes englobantes permet aux annotateurs de dessiner et d'étiqueter des zones rectangulaires sur les images

Le zoom et le déplacement sont activés par défaut, ce qui compte pour les objets petits ou lointains. On peut désactiver les deux avec zoom_enabled: false et pan_enabled: false lorsque les images sont uniformes et que ces contrôles ne font que gêner.

Raccourcis d'étiquettes

Avec le profil de touches par défaut v7, les outils utilisent des lettres : r sélectionne l'outil boîte, p le polygone et b le pinceau. Les raccourcis d'étiquettes se définissent étiquette par étiquette avec key_value, et les chiffres sont le choix sûr, car une étiquette dont le key_value entre en conflit avec une touche d'outil déclenche les deux actions à la fois :

yaml
annotation_schemes:
  - annotation_type: image_annotation
    name: objects
    description: "Annotate all visible objects"
    tools:
      - bbox
    labels:
      - name: person
        color: "#FF6B6B"
        key_value: "1"
 
      - name: car
        color: "#4ECDC4"
        key_value: "2"
 
      - name: motorcycle
        color: "#45B7D1"
        key_value: "3"
 
      - name: bicycle
        color: "#96CEB4"
        key_value: "4"
 
      - name: traffic_light
        color: "#FFEAA7"
        key_value: "5"
 
      - name: stop_sign
        color: "#DDA0DD"
        key_value: "6"

Les couleurs méritent d'être choisies plutôt que subies. Sur des scènes de circulation denses, l'annotateur parcourt l'image à la recherche de ce qu'il a manqué, et deux couleurs proches sur des classes voisines ralentissent ce parcours. Réglez keybinding_profile: legacy si vos annotateurs ont appris les touches de Potato antérieures à la 2.8 et que vous préférez ne pas les former à nouveau.

Ajout d'attributs aux objets

Potato n'a pas de bloc d'attributs par boîte. D'une étiquette image_annotation, seuls name, color et key_value sont lus, et tout le reste du dictionnaire de l'étiquette est ignoré. Une liste imbriquée attributes: n'a donc aucun effet, et aucune question n'apparaît après le tracé d'une boîte.

Il existe deux façons de recueillir la même information. Intégrez la distinction à l'ensemble d'étiquettes, pour que l'attribut fasse partie de ce que l'annotateur choisit :

yaml
annotation_schemes:
  - annotation_type: image_annotation
    name: objects
    description: "Draw a box around each object"
    tools:
      - bbox
    labels:
      - name: person
        color: "#FF6B6B"
      - name: person_occluded
        color: "#C44536"

Ou interrogez l'image dans son ensemble avec un second schéma. Celui-ci porte sur l'élément et non sur une boîte particulière, et c'est là le compromis. Vous apprenez que quelque chose dans l'image était occulté, mais pas quelle boîte était concernée :

yaml
  - annotation_type: multiselect
    name: image_conditions
    description: "Conditions affecting this image"
    labels:
      - Heavy occlusion
      - Truncated objects
      - Low light

L'import depuis VIA est le seul cas où les attributs sont conservés. via_importer lit les region_attributes de chaque région et les intègre à l'étiquette. C'est une notion propre à l'import, pas à la configuration.

Exiger au moins une boîte

Une image sans boîte est ambiguë, car elle peut signifier que l'annotateur n'a rien trouvé ou qu'il a sauté l'élément. min_annotations impose la distinction en refusant toute soumission comportant moins de formes que le minimum, de sorte qu'une image réellement vide exige une étiquette négative explicite :

yaml
annotation_schemes:
  - annotation_type: image_annotation
    name: objects
    description: "Draw a box around every traffic participant"
    tools:
      - bbox
    labels: [...]
    min_annotations: 1

Contrôler la taille d'affichage de l'image

La surface de dessin suit l'image affichée, donc une image affichée en petit donne à l'annotateur un petit canevas. instance_display fixe la taille, et le zoom reste disponible pour le travail de détail :

yaml
instance_display:
  fields:
    - key: image_url
      type: image
      label: "Frame"
      display_options:
        max_width: 1200
        max_height: 800
        zoomable: true

Une configuration de production

La configuration de conduite ci-dessous comporte les cinq classes dont un jeu de données de détection a besoin. Les étiquettes gardent des raccourcis numériques pour que la main gauche de l'annotateur reste sur la rangée des chiffres, et min_annotations: 1 est justifié parce que chaque image de ce corpus contient au moins un usager de la route :

yaml
annotation_task_name: "Autonomous Driving - Object Detection"
task_dir: "."
output_annotation_dir: "annotation_output/"
 
data_files:
  - "data/driving_frames.json"
 
item_properties:
  id_key: id
  text_key: frame_path
 
annotation_schemes:
  - annotation_type: image_annotation
    name: objects
    description: "Annotate all traffic participants and objects"
    tools:
      - bbox
    min_annotations: 1
    labels:
      - name: vehicle
        color: "#FF6B6B"
        key_value: "1"
 
      - name: pedestrian
        color: "#4ECDC4"
        key_value: "2"
 
      - name: cyclist
        color: "#45B7D1"
        key_value: "3"
 
      - name: traffic_sign
        color: "#FFEAA7"
        key_value: "4"
 
      - name: traffic_light
        color: "#DDA0DD"
        key_value: "5"

Cinq classes, c'est déjà la limite de ce que les raccourcis numériques couvrent confortablement. Au-delà de dix, l'annotateur cherche les touches au lieu de lire l'image, et c'est à ce stade qu'il vaut mieux scinder la tâche en deux que d'ajouter une étiquette.

À quoi ressemblent les annotations

Potato stocke toutes les formes d'une image dans un tableau JSON plat, quel que soit l'outil qui les a tracées. Les coordonnées sont normalisées entre 0 et 1 par rapport à l'image, si bien que les annotations restent correctes lorsque l'image est ensuite servie à une autre taille :

json
[
  {
    "type": "bbox",
    "label": "vehicle",
    "color": "#FF6B6B",
    "coordinates": {"x": 0.234, "y": 0.352, "width": 0.120, "height": 0.130}
  },
  {
    "type": "bbox",
    "label": "pedestrian",
    "color": "#4ECDC4",
    "coordinates": {"x": 0.427, "y": 0.370, "width": 0.026, "height": 0.139}
  }
]

Un bbox porte sa géométrie sous coordinates, sous la forme {x, y, width, height}. Les polygones portent une liste de points sous la même clé, et les masques portent un encodage run-length sous rle.

Exporter pour l'entraînement

Le code d'entraînement des détecteurs lit COCO ou YOLO, et Potato écrit les deux :

bash
python -m potato.export --config config.yaml --format coco --output ./export/
python -m potato.export --config config.yaml --format yolo --output ./export/

Les deux exports diffèrent par plus que la syntaxe. COCO écrit un unique annotations.json avec des boîtes en pixels au format [x, y, width, height], et ne copie pas les images, donc les valeurs de file_name pointent vers l'emplacement actuel des images. YOLO écrit un fichier texte par image avec des coordonnées de centre normalisées, répartit images et étiquettes dans des répertoires train/ et val/, et ajoute data.yaml et classes.txt pour qu'un entraînement puisse lire la liste des classes sans qu'on la lui fournisse séparément.

Garder des boîtes cohérentes

Tracez des boîtes serrées autour de l'objet, car chaque pixel d'arrière-plan dans la boîte est un pixel que le modèle apprend à considérer comme premier plan. Consignez par écrit la façon de traiter les cas délicats (occlusion, objets coupés au bord de l'image, reflets) et examinez ensemble un lot d'exemples dès la première semaine, tant que modifier la consigne coûte encore peu. Surveillez le nombre de boîtes et la distribution des tailles par annotateur pendant l'étude, car un changement soudain signifie généralement qu'une personne a commencé à interpréter une règle autrement, et non que les images ont changé.

Prochaines étapes

Pour les autres options d'image, consultez Annotation d'images.