Bounding Boxes für die Objekterkennung zeichnen
Baue in Potato eine Aufgabe zur Objekterkennung, von einer Startkonfiguration mit drei Labels bis zu einer Produktivkonfiguration für Fahraufnahmen, und exportiere nach COCO oder YOLO.
Dieses Tutorial baut in Potato eine Annotationsaufgabe zur Objekterkennung auf, von einer Konfiguration mit drei Labels bis zum COCO- oder YOLO-Export, auf dem ein Detektor trainiert wird. Die vollständige Liste der Bildwerkzeuge und ihrer Optionen steht in der Dokumentation zur Bildannotation.
Die Datendatei
Jede Zeile der Datendatei ist ein Bild. Potato braucht eine Kennung und ein Feld mit der URL oder dem Pfad des Bildes, und item_properties legt fest, welches Feld welches ist:
{"id": "img_001", "image_url": "https://example.com/street_001.jpg"}
{"id": "img_002", "image_url": "/static/images/street_002.jpg"}Ein relativer Pfad wird gegen media_directory aufgelöst, lokale Bilder brauchen also keinen laufenden Dateiserver.
Eine minimale Konfiguration
Das Schema image_annotation stellt die Zeichenfläche bereit. Es braucht einen Namen, eine Beschreibung, die Annotierende als Anweisung lesen, die zu aktivierenden Werkzeuge und die Labelmenge:
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"Drei Labels sind ein bewusst gewählter Anfang. Jedes zusätzliche Label ist eine Entscheidung, die Annotierende bei jedem Objekt treffen müssen, und ein Grenzfall, für den sie eine Regel brauchen. Fang deshalb mit den Klassen an, die das Modell tatsächlich braucht, und ergänze den Rest, sobald die Richtlinien tragen.
Starte den Server und öffne die Aufgabe:
potato start config.yaml -p 8000Was Annotierende tun
Annotierende wählen ein Label und ziehen dann um jedes Objekt ein Rechteck auf, dessen Ecken sie nachjustieren, bis die Box eng anliegt:
Mit dem Bounding-Box-Werkzeug zeichnen und labeln Annotierende rechteckige Bereiche auf Bildern
Zoomen und Verschieben sind standardmäßig aktiv, was bei kleinen oder weit entfernten Objekten wichtig ist. Beides lässt sich mit zoom_enabled: false und pan_enabled: false abschalten, wenn die Bilder einheitlich sind und die zusätzlichen Bedienelemente nur stören.
Tastenkürzel für Labels
Im Standard-Tastenprofil v7 liegen die Werkzeuge auf Buchstabentasten: r wählt das Box-Werkzeug, p das Polygon und b den Pinsel. Tastenkürzel für Labels werden pro Label mit key_value gesetzt, und Ziffern sind dabei die sichere Wahl, denn ein Label, dessen key_value mit einer Werkzeugtaste kollidiert, löst beide Aktionen gleichzeitig aus:
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"Die Farben lohnen eine bewusste Wahl, statt die Vorgaben zu übernehmen. In dichten Verkehrsszenen suchen Annotierende das Bild nach Übersehenem ab, und zwei ähnliche Farben bei benachbarten Klassen verlangsamen diese Suche. Setze keybinding_profile: legacy, wenn deine Annotierenden die Tasten von Potato vor 2.8 gelernt haben und du sie nicht umschulen willst.
Attribute für Objekte ergänzen
Potato hat keinen Attributblock pro Box. Von einem image_annotation-Label werden name, color und key_value gelesen, alles andere im Label-Dictionary wird verworfen. Eine verschachtelte attributes:-Liste bewirkt also nichts, und nach dem Zeichnen einer Box erscheint keine Abfrage.
Dieselbe Information lässt sich auf zwei Wegen erfassen. Nimm die Unterscheidung in die Labelmenge auf, sodass das Attribut Teil dessen ist, was Annotierende auswählen:
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"Oder frag mit einem zweiten Schema nach dem Bild als Ganzem. Das gilt dann für das Element und nicht für eine einzelne Box, und darin liegt der Kompromiss: Du erfährst, dass im Bild etwas verdeckt war, aber nicht, welche Box es betraf:
- annotation_type: multiselect
name: image_conditions
description: "Conditions affecting this image"
labels:
- Heavy occlusion
- Truncated objects
- Low lightBeim Import aus VIA bleiben Attribute als einziger Fall erhalten. via_importer liest die region_attributes jeder Region und übernimmt sie ins Label. Das ist ein Konzept des Imports, nicht der Konfiguration.
Mindestens eine Box verlangen
Ein Bild ohne Boxen ist mehrdeutig, denn es kann heißen, dass nichts gefunden wurde, oder dass jemand das Element übersprungen hat. min_annotations erzwingt die Unterscheidung, indem es eine Abgabe mit weniger Formen als dem Mindestwert ablehnt. Ein tatsächlich leeres Bild braucht dann ein ausdrückliches Negativ-Label:
annotation_schemes:
- annotation_type: image_annotation
name: objects
description: "Draw a box around every traffic participant"
tools:
- bbox
labels: [...]
min_annotations: 1Steuern, wie groß das Bild dargestellt wird
Die Zeichenfläche folgt dem dargestellten Bild, ein klein dargestelltes Bild gibt Annotierenden also eine kleine Zeichenfläche. instance_display legt die Größe fest, und Zoomen bleibt für Detailarbeit verfügbar:
instance_display:
fields:
- key: image_url
type: image
label: "Frame"
display_options:
max_width: 1200
max_height: 800
zoomable: trueEine Produktivkonfiguration
Die Fahrkonfiguration unten enthält die fünf Klassen, die ein Detektionsdatensatz braucht. Die Labels behalten Zifferntasten, damit die linke Hand der Annotierenden auf der Zahlenreihe bleibt, und min_annotations: 1 passt, weil jedes Bild in diesem Korpus mindestens einen Verkehrsteilnehmer enthält:
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"Fünf Klassen sind schon an der Grenze dessen, was Zifferntasten bequem abdecken. Ab zehn suchen Annotierende nach Tasten, statt das Bild zu lesen, und ab diesem Punkt ist es besser, die Aufgabe in zwei aufzuteilen, als ein weiteres Label hinzuzufügen.
Wie die Annotationen aussehen
Potato speichert alle Formen eines Bildes in einem flachen JSON-Array, unabhängig davon, mit welchem Werkzeug sie gezeichnet wurden. Die Koordinaten sind relativ zum Bild auf den Bereich 0 bis 1 normalisiert, sodass die Annotationen stimmen, auch wenn das Bild später in einer anderen Größe ausgeliefert wird:
[
{
"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}
}
]Eine bbox trägt ihre Geometrie unter coordinates als {x, y, width, height}. Polygone tragen unter demselben Schlüssel eine Liste von Punkten, Masken dagegen eine Lauflängenkodierung unter rle.
Export fürs Training
Trainingscode für Detektoren liest COCO oder YOLO, und Potato schreibt beides:
python -m potato.export --config config.yaml --format coco --output ./export/
python -m potato.export --config config.yaml --format yolo --output ./export/Die beiden Exporte unterscheiden sich in mehr als der Syntax. COCO schreibt eine einzige annotations.json mit Pixel-Boxen als [x, y, width, height] und kopiert die Bilder nicht, die file_name-Werte zeigen also dorthin, wo die Bilder bereits liegen. YOLO schreibt eine Textdatei pro Bild mit normalisierten Mittelpunktkoordinaten, teilt Bilder und Labels auf die Verzeichnisse train/ und val/ auf und legt data.yaml und classes.txt an, damit ein Trainingslauf die Klassenliste lesen kann, ohne dass man sie ihm separat übergibt.
Die Boxen konsistent halten
Zieh die Boxen eng um das Objekt, denn jedes Hintergrundpixel in der Box ist ein Pixel, das das Modell als Vordergrund zu bezeichnen lernt. Halte schriftlich fest, wie mit den schwierigen Fällen umzugehen ist (Verdeckung, am Bildrand abgeschnittene Objekte, Spiegelungen), und geht in der ersten Woche gemeinsam einen Stapel Beispiele durch, solange eine Änderung der Richtlinie noch wenig kostet. Beobachte während der Studie die Anzahl der Boxen und die Größenverteilung für jede annotierende Person, denn eine plötzliche Verschiebung bedeutet meist, dass eine Person eine Regel anders auslegt, und nicht, dass sich die Bilder geändert haben.
Nächste Schritte
- Ergänze Polygon-Annotation, wenn Boxen für die Aufgabe zu grob sind
- Nutze Keypoint-Sets für Pose Estimation
- Richte Qualitätskontrolle ein, bevor die Studie über eine Handvoll Annotierender hinauswächst
Die übrigen Bildoptionen findest du unter Bildannotation.