Objekte mit ByteTrack, BoT-SORT und TrackTrack verfolgen
Gib jedem Objekt über mehrere Bilder hinweg eine stabile ID, wähle einen Tracker und passe seine Schwellenwerte an deinen Detektor an.
Jede Zählung, Verweildauer und Geschwindigkeitsschätzung hängt von einer Frage ab: Ist ID 17 in diesem Bild dasselbe Objekt wie ID 17 im vorherigen Bild? Im selben 62 Bilder langen Clip mit etwa 30 Fußgängern und demselben Detektor fand ByteTrack 32 IDs, während TrackTrack mit Standardeinstellungen 9 fand. Die Wahl und Abstimmung des Trackers gehören zum Modell; eine falsche Wahl verfälscht unbemerkt alle nachfolgenden Zahlen.
Praxisnah
Was ein Tracker leistet#

Die Beschriftungen und Spuren in diesem Bild stammen vom Tracker. Jede ID ist ein Track, also eine Hypothese zu einem realen Objekt; die Spur zeigt dessen jüngsten Verlauf. In jedem Bild sagt der Tracker mit einem Kalman-Filter voraus, wo sich jeder Track befinden sollte, und ordnet dann die neuen Erkennungen diesen Vorhersagen anhand der Überlappung der Boxen (und optional des Erscheinungsbilds) zu:
Tracks, die über track_buffer Bilder hinweg keiner Erkennung zugeordnet werden, werden gelöscht. Das ist der gesamte Mechanismus; seine Schwellenwerte bestimmen alles Weitere.
Einen Tracker auswählen#
Der Tracking-Modus bietet sechs Tracker: BoT-SORT, ByteTrack, OC-SORT, Deep OC-SORT, FastTracker und TrackTrack (Standard, wenn du kein tracker angibst). Drei decken die meisten Anforderungen ab:
| Tracker | Abgleichmerkmale (Standardkonfiguration) | Wann du ihn verwenden solltest |
|---|---|---|
| ByteTrack | Bewegung und Box-Überlappung sowie ein zweiter Durchlauf, der Boxen mit geringer Konfidenz berücksichtigt | Feste Kameras, kleine oder unsichere Detektoren, wenn hoher Durchsatz wichtig ist |
| BoT-SORT | Abgleich wie bei ByteTrack, ergänzt um Bewegungsausgleich der Kamera (gmc_method: sparseOptFlow) | Bei bewegten oder wackelnden Kameras; setze with_reid: True für Menschenmengen und lange Verdeckungen |
| TrackTrack | Kostenfunktion mit mehreren Merkmalen (Boxform, Konfidenz, Winkel), trackbezogene Initialisierung und Bewegungsausgleich der Kamera | Erkennungen mit hoher Konfidenz von einem leistungsfähigen, gut trainierten Modell |
Der Abgleich anhand des Erscheinungsbilds von BoT-SORT (Wiedererkennung) ist standardmäßig deaktiviert; mit model: auto verwendet er die eigenen Merkmale des Detektors, sodass die Aktivierung kaum zusätzlichen Rechenaufwand verursacht.
Tracker auf einem Clip vergleichen#
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
for tracker in ("bytetrack.yaml", "botsort.yaml", "tracktrack.yaml"):
ids, frames = set(), 0
for r in model.track(video, stream=True, tracker=tracker, classes=[0], verbose=False):
frames += 1
if r.boxes.is_track:
ids.update(r.boxes.id.int().tolist())
print(f"{tracker:16s} {frames} frames, {len(ids)} unique person IDs")bytetrack.yaml 62 frames, 32 unique person IDs
botsort.yaml 62 frames, 33 unique person IDs
tracktrack.yaml 62 frames, 9 unique person IDsDer Clip zeigt von oben etwa 30 Menschen, die einen Platz überqueren, daher liegen ByteTrack und BoT-SORT nahe am tatsächlichen Ergebnis. TrackTrack ist nicht defekt: Ein Track wird erst oberhalb von new_track_thresh: 0.7 gestartet und der Abgleich beginnt erst oberhalb von track_high_thresh: 0.6. Die mediane Konfidenz für Personen von YOLO26n liegt in diesem Clip bei 0,53, und nur 17 % der Erkennungen erreichen 0,7. Die meisten Menschen erhalten nie eine ID. Die Entscheidungsregel: Vergleiche die Schwellenwerte des Trackers mit der Konfidenzverteilung deines Detektors, bevor du einer Zählung vertraust.
IDs in einer Pipeline verwenden#
from collections import defaultdict
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
counts = defaultdict(set)
for r in model.track(video, stream=True, tracker="bytetrack.yaml", verbose=False):
if not r.boxes.is_track: # no confirmed tracks in this frame yet
continue
for cls, tid in zip(r.boxes.cls.int().tolist(), r.boxes.id.int().tolist()):
counts[r.names[cls]].add(tid)
for cls, ids in counts.items():
print(f"{cls}: {len(ids)} unique objects")person: 32 unique objectsEine Menge pro Klasse zählt jede ID nur einmal, egal in wie vielen Bildern sie erscheint. Das Ergebnis sind also Objekte und keine Erkennungen. stream=True liefert die Ergebnisse Bild für Bild, statt das gesamte Video im Speicher zu halten. Bereichszählung, Wärmekarten und Abstandsmessung sind einfache Erweiterungen dieser Schleife.
Selbst eingelesene Bilder verfolgen#
Bei einem Pfad oder einer URL wird der Tracker-Zustand automatisch verwaltet. Wenn die Bilder von deinem eigenen Decoder, einer Webcam oder einer RTSP-Kamera kommen, setze persist=True, damit jeder Aufruf dieselbe Sequenz fortsetzt (die Dokumentation zum Vorhersagemodus listet alle Quelltypen auf):
import cv2
from ultralytics import YOLO
from ultralytics.utils.downloads import safe_download
model = YOLO("yolo26n.pt")
video = safe_download("https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4")
cap = cv2.VideoCapture(str(video)) # or 0 for a webcam, or an rtsp:// URL
seen = set()
while True:
ok, frame = cap.read()
if not ok:
break
r = model.track(frame, persist=True, tracker="bytetrack.yaml", classes=[0], verbose=False)[0]
if r.boxes.is_track:
seen.update(r.boxes.id.int().tolist()) # your logic: dwell time, trajectories, alerts
cap.release()
print(f"{len(seen)} unique IDs")32 unique IDsDas Ergebnis entspricht der Übergabe des Pfads, denn persist=True hat über alle 62 Aufrufe hinweg denselben Tracker aktiv gehalten.
Einen Tracker auf deinen Detektor abstimmen#
Kopiere eine mitgelieferte Konfiguration, senke die Schwellenwerte, die nicht zu deinem Detektor passen, und übergib die neue Datei:
from pathlib import Path
from ultralytics import YOLO
from ultralytics.utils import ROOT
cfg = (ROOT / "cfg/trackers/tracktrack.yaml").read_text() # packaged defaults
for old, new in (
("track_high_thresh: 0.6", "track_high_thresh: 0.3"),
("track_low_thresh: 0.25", "track_low_thresh: 0.1"),
("new_track_thresh: 0.7", "new_track_thresh: 0.35"),
):
cfg = cfg.replace(old, new)
Path("tracktrack_tuned.yaml").write_text(cfg)
model = YOLO("yolo26n.pt")
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
for tracker in ("tracktrack.yaml", "tracktrack_tuned.yaml"):
ids = set()
for r in model.track(video, stream=True, tracker=tracker, classes=[0], verbose=False):
if r.boxes.is_track:
ids.update(r.boxes.id.int().tolist())
print(f"{tracker:22s} {len(ids)} unique person IDs")tracktrack.yaml 9 unique person IDs
tracktrack_tuned.yaml 27 unique person IDsIndem du die Schwellenwerte knapp unter der medianen Konfidenz des Detektors festlegst, stieg die Anzahl der IDs bei TrackTrack von 9 auf 27 und lag damit nahe an der manuellen Zählung. Die Einstellungen, die alle Tracker gemeinsam haben:
| Einstellung | ByteTrack-Standardwert | Erhöhen, um | Senken, um |
|---|---|---|---|
track_high_thresh | 0.25 | Schwache Erkennungen beim ersten Abgleich ignorieren | Einen Detektor mit niedriger Konfidenz verfolgen |
new_track_thresh | 0.25 | Kurzlebige falsche Tracks vermeiden | Tracks für schwach erkennbare Objekte starten |
track_buffer | 30 Bilder | Längere Verdeckungen überstehen | IDs verschwundener Objekte früher freigeben |
match_thresh | 0.8 | Großzügiger abgleichen (schnelle Bewegung, sprunghafte Boxen) | Strenger abgleichen (Menschenmengen) |
Stolperfallen#
Symptom: Deutlich weniger IDs als Objekte, besonders bei einem kleinen Modell. Lösung: Gib die mediane Detektionskonfidenz aus (siehe Lösung) und setze new_track_thresh und track_high_thresh knapp darunter.
Symptom: IDs werden bei jedem Frame zurückgesetzt, wenn du model.track(frame) selbst aufrufst, oder wechseln zwischen Objekten, wenn zwei Kameras ein Modell verwenden. Lösung: Übergib persist=True für aufeinanderfolgende Frames desselben Streams und verwende für jede Kamera eine eigene Modellinstanz (oder nutze eine .streams-Quelle, die für jeden Stream einen eigenen Tracker verwaltet).
Symptom: Die ID eines geparkten Autos ändert sich alle paar Frames. Lösung: Der Tracker beginnt neue Tracks, anstatt alte zuzuordnen. Prüfe zuerst die Konfidenz des Detektors für das Objekt und erhöhe anschließend match_thresh und track_buffer.
Lösung anzeigen
Ermittle zuerst die Konfidenzwerte des Detektors und lege dann die Schwellenwerte knapp darunter fest:
import torch
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
conf = torch.cat([r.boxes.conf for r in model.predict(video, stream=True, classes=[0], verbose=False)])
print(f"median {conf.median():.2f}, share >= 0.7: {(conf >= 0.7).float().mean():.0%}")median 0.53, share >= 0.7: 17%Für den Clip vom Platz zeigt die Tabelle: ByteTrack 32, BoT-SORT 33, TrackTrack 9, abgestimmtes TrackTrack 27, manuelle Zählung etwa 30. Nur 17 % der Erkennungen überschreiten new_track_thresh: 0.7 von TrackTrack, daher ist es richtig, diesen Wert auf 0,35 zu senken (mit track_high_thresh: 0.3); für diese feste Kamera mit Blick von oben ist ByteTrack ohne weitere Anpassungen die einfachere Wahl.