Skip to content

Annotation d'images

Configurez l'annotation d'images dans Potato avec boîtes englobantes, polygones, masques et points de repère. Affichez les images avec instance_display et exportez en COCO ou YOLO.

Potato prend en charge l'annotation d'images pour les tâches de classification, de détection d'objets, de segmentation et de points clés.

Afficher une image

Afficher une image et recueillir une annotation sont deux réglages distincts. instance_display décrit ce que voit l'annotateur, et annotation_schemes ce à quoi il répond. Comme les deux restent séparés, n'importe quel type de contenu peut accompagner n'importe quel type de question :

yaml
instance_display:
  fields:
    - key: image_url          # Field name in your data file
      type: image
      label: "Image to classify"
      display_options:
        max_width: 600
        zoomable: true

Le schéma image_annotation sert à dessiner sur une image, pas à l'afficher. Une tâche de classification n'a besoin que du champ d'affichage ci-dessus et d'un schéma radio ou multiselect.

Options d'affichage

OptionDescription
max_widthLargeur d'affichage maximale en pixels
max_heightHauteur d'affichage maximale en pixels
zoomableActive le zoom au clic
object_fitManière dont l'image remplit son cadre
alt_textTexte alternatif pour les lecteurs d'écran

Un nom d'option que Potato ne reconnaît pas est une erreur de configuration et non une clé ignorée en silence, et le message propose l'option réelle la plus proche.

Format des données

Référencez les images dans votre fichier de données :

json
{"id": "img_001", "image_url": "https://example.com/photo_001.jpg"}
{"id": "img_002", "image_url": "/static/images/photo_002.png"}

data_files est une liste de chemins, et item_properties fait correspondre vos noms de champs à ceux que lit Potato :

yaml
data_files:
  - "data/image_tasks.json"
 
item_properties:
  id_key: id
  text_key: image_url   # The field holding the image URL

Classification d'images

Classer des images entières :

yaml
annotation_schemes:
  - annotation_type: radio
    name: category
    description: "What is shown in this image?"
    labels:
      - Cat
      - Dog
      - Bird
      - Other
 
  - annotation_type: multiselect
    name: attributes
    description: "Select all that apply"
    labels:
      - Indoor
      - Outdoor
      - Multiple animals
      - Human present

Classification multi-étiquettes

yaml
annotation_schemes:
  - annotation_type: multiselect
    name: objects
    description: "What objects are visible?"
    labels:
      - Person
      - Car
      - Building
      - Tree
      - Animal
      - Furniture
      - Food
      - Electronic device

Évaluation de la qualité d'image

yaml
annotation_schemes:
  - annotation_type: likert
    name: quality
    description: "Overall image quality"
    size: 5
    min_label: "Very poor"
    max_label: "Excellent"
 
  - annotation_type: multiselect
    name: issues
    description: "Select any quality issues"
    labels:
      - Blurry
      - Overexposed
      - Underexposed
      - Noisy
      - Low resolution
      - Watermark visible

Dessiner sur les images

Le schéma image_annotation exige à la fois tools et labels. Donner à chaque étiquette une couleur et une key_value vaut les quelques lignes de plus, car les annotateurs attribuent une étiquette au clavier bien plus vite qu'à la souris :

yaml
annotation_schemes:
  - annotation_type: image_annotation
    name: object_detection
    description: "Draw boxes around objects"
    tools:
      - bbox
      - polygon
    labels:
      - name: person
        color: "#FF6B6B"
        key_value: "1"
      - name: vehicle
        color: "#4ECDC4"
        key_value: "2"
      - name: animal
        color: "#45B7D1"
        key_value: "3"
    min_annotations: 1
    zoom_enabled: true
    pan_enabled: true

color doit être en hexadécimal (#rgb, #rrggbb ou #rrggbbaa). Les noms de couleurs CSS et rgb() ne sont pas lus. Les formes auraient l'air correctes, mais les masques sont peints pixel par pixel et se rabattent sur le rouge.

Outils disponibles

OutilDescription
bboxBoîtes englobantes rectangulaires
polygonPolygones fermés à plusieurs points
polylineTracés ouverts à plusieurs points, pour les marquages de voie, les vaisseaux, les fissures, les traits de côte
ellipseEllipses et cercles, pour les cellules, les noyaux, les roues, les visages
keypoint_setSquelettes ordonnés, pour la pose humaine ou animale et les points de repère du visage
cuboid_2dBoîtes 3D projetées dans l'image, à la manière de KITTI
samBaguette magique : cliquez sur un objet et un modèle le segmente
freeformDessin à main levée
landmarkMarqueurs d'un seul point
brushPinceau de segmentation pour les masques au niveau du pixel
eraserSupprime des zones du masque
fillRemplissage par diffusion des zones fermées

Un polygone est fermé et délimite une surface. Une polyligne est ouverte et a une longueur mais pas d'intérieur. La distinction compte à l'export, où une polyligne est écrite avec area: 0 et n'est jamais traitée comme une région.

Annotation par polygones

Pour les régions non rectangulaires :

yaml
annotation_schemes:
  - annotation_type: image_annotation
    name: regions
    description: "Outline regions of interest"
    tools:
      - polygon
    labels:
      - name: Building
      - name: Road
      - name: Vegetation
      - name: Water

Masques de segmentation

Pour le travail au niveau du pixel, activez les outils de peinture. Les masques sont stockés en codage par plages (run-length encoding) plutôt qu'en tableaux par pixel, ce qui permet de garder petit un masque couvrant toute l'image :

yaml
annotation_schemes:
  - annotation_type: image_annotation
    name: segmentation
    description: "Paint regions using the brush tool"
    tools:
      - brush
      - eraser
      - fill
    labels:
      - name: road
        color: "#45B7D1"
      - name: sidewalk
        color: "#96CEB4"
    brush_size: 20
    mask_opacity: 0.5
    mask_mode: semantic

mask_mode: semantic fusionne tous les traits d'une même classe en une seule région. Utilisez instance lorsque deux objets de la même classe doivent rester distincts.

Format de sortie

Les annotations sont stockées dans un tableau JSON plat, avec toutes les formes et tous les masques dans la même liste. Les coordonnées sont normalisées entre 0 et 1 par rapport à l'image, si bien que les annotations restent justes lorsque l'image est servie à une autre taille :

json
[
  {
    "type": "bbox",
    "label": "person",
    "color": "#FF6B6B",
    "coordinates": {"x": 0.125, "y": 0.104, "width": 0.3125, "height": 0.625}
  },
  {
    "type": "polygon",
    "label": "vehicle",
    "color": "#4ECDC4",
    "coordinates": [
      {"x": 0.02, "y": 0.04}, {"x": 0.20, "y": 0.04},
      {"x": 0.20, "y": 0.21}, {"x": 0.02, "y": 0.21}
    ]
  },
  {
    "type": "mask",
    "label": "road",
    "color": "#45B7D1",
    "rle": {"counts": [12, 40, 8], "size": [480, 640]}
  }
]

La clé de géométrie dépend du type :

TypeClé de géométrieForme
bboxcoordinates{x, y, width, height}, normalisé
polygoncoordinatesliste de {x, y}, normalisés
landmarkcoordinates{x, y}, normalisé
freeformcoordinates{path, left, top, scaleX, scaleY}
maskrle{counts: [ints], size: [height, width]}

rle.size vaut [height, width], dans cet ordre. Pour convertir vers et depuis ces formes en Python, utilisez normalize_annotation_object() et to_client_object() de potato.export.cv_utils plutôt que de lire les champs directement.

Origine d'une forme

Une fois stockées, une détection acceptée d'un modèle et une boîte dessinée à la main sont identiques, c'est pourquoi chaque forme enregistre sa propre origine. Sans cela, un projet qui pré-étiquette avec un modèle ne peut pas calculer son taux d'acceptation à partir de ses propres données :

json
{
  "type": "bbox",
  "label": "person",
  "coordinates": {"x": 0.125, "y": 0.104, "width": 0.3125, "height": 0.625},
  "source": "ai",
  "ai_model": "yolov8n",
  "confidence": 0.82,
  "edited": true
}
CléSignification
sourcehuman (dessinée dans le navigateur), ai (proposée par un modèle et acceptée par l'annotateur), import (arrivée avec les données)
ai_modelLe modèle concerné, lorsque l'endpoint l'indique
confidenceLe score que le détecteur a lui-même attribué à cette forme
editedL'annotateur a depuis déplacé, redimensionné ou réétiqueté une forme qui n'était pas la sienne
carried_overRecopiée depuis l'image précédente plutôt que créée sur celle-ci

edited distingue le fait d'accepter une boîte telle quelle de celui de l'accepter puis de la corriger. Seul le premier cas constitue un accord avec le modèle.

Relire des annotations existantes

Pour relire des formes qui existent déjà, importez-les plutôt que de les ajouter à un champ de données. potato import transforme un fichier COCO en projet prêt à lancer et marque chaque forme avec source: import :

bash
potato import --input instances_val2017.json \
    --image-dir /data/val2017 \
    --image-url-prefix /files \
    --output-dir my-project/ \
    --schema-name object_detection
 
potato start my-project/config.yaml -p 8000

Les annotateurs corrigent ensuite les formes importées sur place, et l'export conserve la répartition entre humain et modèle sur l'ensemble de l'aller-retour.

Comparaison d'images

Comparez deux images avec le schéma pairwise. items_key désigne le champ de données qui contient la paire :

yaml
annotation_schemes:
  - annotation_type: pairwise
    name: preference
    description: "Which image looks better?"
    mode: binary
    items_key: images
    show_labels: true
    labels:
      - "Original"
      - "Edited"
    allow_tie: true
    tie_label: "About the same"

Légendage d'images

yaml
annotation_schemes:
  - annotation_type: text
    name: caption
    description: "Write a caption for this image"
    rows: 4
    placeholder: "Describe what you see..."

Relecture de la qualité des légendes

Affichez l'image et la légende générée côte à côte, puis évaluez la légende :

yaml
instance_display:
  fields:
    - key: image_url
      type: image
      label: "Image"
    - key: generated_caption
      type: text
      label: "Generated caption"
 
annotation_schemes:
  - annotation_type: likert
    name: accuracy
    description: "How accurate is this caption?"
    size: 5
    min_label: "Very inaccurate"
    max_label: "Very accurate"
 
  - annotation_type: likert
    name: fluency
    description: "How natural is the language?"
    size: 5
    min_label: "Very awkward"
    max_label: "Very natural"
 
  - annotation_type: text
    name: improved_caption
    description: "Suggest a better caption (optional)"
    rows: 4
    label_requirement:
      required: false

Modération de contenu

yaml
annotation_schemes:
  - annotation_type: radio
    name: safe_for_work
    description: "Is this image safe for work?"
    labels:
      - Safe
      - Questionable
      - Not Safe
 
  - annotation_type: multiselect
    name: violation_types
    description: "Select all violations (if any)"
    labels:
      - Violence
      - Adult content
      - Hate symbols
      - Graphic content
      - Spam/advertisement

Formats d'échange

Potato lit le JSON COCO, y compris tous les encodages de segmentation et les régions de foule (crowd), et écrit du COCO, du YOLO, du Pascal VOC et des PNG de masque par étiquette :

bash
python -m potato.export -c my-project/config.yaml -f coco -o ./export/

YOLO et Pascal VOC ne transportent que des boîtes englobantes, donc les autres formes sont réduites à leur boîte englobante.

Exemple complet : relecture d'une détection d'objets

yaml
annotation_task_name: "Object Detection Verification"
task_dir: "."
 
data_files:
  - "data/detections.json"
 
item_properties:
  id_key: id
  text_key: image_url
 
instance_display:
  fields:
    - key: image_url
      type: image
      label: "Image"
      display_options:
        max_width: 1000
        zoomable: true
 
annotation_schemes:
  # Correct the boxes
  - annotation_type: image_annotation
    name: objects
    description: "Verify and correct object boxes"
    tools:
      - bbox
    labels:
      - name: Person
        key_value: "1"
      - name: Vehicle
        key_value: "2"
      - name: Animal
        key_value: "3"
      - name: Object
        key_value: "4"
    zoom_enabled: true
    pan_enabled: true
 
  # Overall assessment
  - annotation_type: radio
    name: prediction_quality
    description: "How accurate were the predictions?"
    labels:
      - All correct
      - Minor corrections needed
      - Major corrections needed
      - Mostly incorrect
 
  - annotation_type: number
    name: missed_objects
    description: "How many objects were missed?"
    min: 0
    max: 50
 
  - annotation_type: text
    name: notes
    description: "Any issues or comments?"
    rows: 4
    label_requirement:
      required: false
 
output_annotation_dir: "output/"
export_annotation_format: jsonl
 
user_config:
  allow_all_users: true

Démarrez le serveur :

bash
potato start config.yaml -p 8000

Conseils de performance

  1. Redimensionnez avant d'annoter : les grandes images sources ralentissent le chargement sans améliorer l'annotation
  2. JPEG pour les photos : fichiers plus légers, chargement plus rapide
  3. PNG pour les graphiques : meilleur rendu des schémas et des captures d'écran
  4. Plafonnez la taille d'affichage : définissez max_width pour que le navigateur n'ait pas à redimensionner une image énorme à chaque instance
  5. Prétraitez de façon homogène : normalisez tailles et formats sur l'ensemble du jeu de données