Ultralytics YOLO27: Iscriviti alla lista d'attesa.
Get Started
Ultralytics YOLO in produzione·Traccia e crea pipeline·Lezione 5/9
Lezioneintermedio

Traccia gli oggetti con ByteTrack, BoT-SORT e TrackTrack

Assegna a ogni oggetto un ID stabile tra i fotogrammi, scegli un tracker e regola le sue soglie in base al tuo rilevatore.

Ogni conteggio, tempo di permanenza e stima della velocità dipende da una domanda: l'ID 17 in questo fotogramma identifica lo stesso oggetto dell'ID 17 nel fotogramma precedente? Nella stessa clip di 62 fotogrammi, con circa 30 pedoni e lo stesso rilevatore, ByteTrack ha trovato 32 ID e TrackTrack con la configurazione predefinita ne ha trovati 9. La scelta e la regolazione del tracker fanno parte del modello: se sbagli, tutti i numeri successivi diventano inaffidabili senza che te ne accorga.

Esito

Esegui tre tracker su un video, spiega il numero di ID ottenuti in base ai punteggi di confidenza del rilevatore, usa box.id in una pipeline e correggi un tracker non adatto con un file YAML regolato.

Percorso rapido
Se sai già come muoverti, ecco la versione breve.
  1. model.track(source, stream=True, tracker="bytetrack.yaml"); ogni riquadro ottiene un id stabile.

  2. Fornisci tu i fotogrammi? Passa persist=True in modo che gli ID persistano tra le chiamate; usa un tracker per telecamera.

  3. Il valore predefinito è tracktrack.yaml; ByteTrack è veloce e tollerante; BoT-SORT aggiunge la compensazione del movimento della telecamera, con ReID facoltativo.

  4. Troppi pochi ID: misura i punteggi di confidenza del rilevatore e abbassa new_track_thresh e track_high_thresh in una copia del file YAML.

Pratico

Cosa aggiunge un tracker#

Il tracciamento del traffico autostradale con Ultralytics YOLO: ogni auto, autobus e camion mantiene un ID numerato (auto #12, autobus #21, camion #16) e una linea colorata ne segna il percorso recente

Le etichette e le tracce in questo fotogramma sono il risultato prodotto da un tracker. Ogni ID è una traccia, cioè un'ipotesi relativa a un oggetto reale, e la traccia mostra la sua cronologia recente. A ogni fotogramma, il tracker prevede dove dovrebbe trovarsi ciascuna traccia usando un filtro di Kalman, quindi abbina le nuove rilevazioni a quelle previsioni in base alla sovrapposizione dei riquadri (e, facoltativamente, all'aspetto):

Le tracce che non trovano corrispondenza per track_buffer fotogrammi vengono eliminate. È tutto qui il meccanismo, e le sue soglie determinano tutto ciò che segue.

Scegli un tracker#

La modalità di tracciamento include sei tracker: BoT-SORT, ByteTrack, OC-SORT, Deep OC-SORT, FastTracker e TrackTrack (il valore predefinito se non passi tracker). Tre coprono la maggior parte delle esigenze:

TrackerCriteri di corrispondenza (configurazione predefinita)Sceglilo quando
ByteTrackMovimento e sovrapposizione dei riquadri, più un secondo passaggio che recupera i riquadri con bassa confidenzaTelecamere fisse, rilevatori piccoli o incerti, priorità alla produttività
BoT-SORTCorrispondenza in stile ByteTrack più compensazione del movimento della telecamera (gmc_method: sparseOptFlow)Telecamere in movimento o soggette a vibrazioni; imposta with_reid: True per folle e occlusioni prolungate
TrackTrackCosto basato su più criteri (forma del riquadro, confidenza, angolo), inizializzazione consapevole delle tracce, compensazione del movimento della telecameraRilevazioni con elevata confidenza da un modello robusto e ben addestrato

La corrispondenza basata sull'aspetto di BoT-SORT (re-identificazione) è disattivata per impostazione predefinita; con model: auto riutilizza le caratteristiche del rilevatore, quindi attivarla comporta un sovraccarico minimo.

Confronta i tracker su una clip#

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 IDs

La clip mostra dall'alto circa 30 persone che attraversano una piazza, quindi ByteTrack e BoT-SORT si avvicinano al conteggio reale. TrackTrack non è difettoso: avvia una traccia solo sopra new_track_thresh: 0.7 e cerca corrispondenze iniziali solo sopra track_high_thresh: 0.6, mentre la confidenza mediana delle persone rilevate da YOLO26n in questa clip è 0.53 e solo il 17% delle rilevazioni raggiunge 0.7. La maggior parte delle persone non riceve mai un ID. La regola decisionale: confronta le soglie del tracker con la distribuzione dei punteggi di confidenza del rilevatore prima di fidarti di un conteggio.

Usa gli ID in una pipeline#

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 objects

Un set per classe conta ogni ID una sola volta, indipendentemente dal numero di fotogrammi in cui compare, quindi il risultato è il numero di oggetti, non di rilevazioni. stream=True restituisce i risultati un fotogramma alla volta, invece di tenere l'intero video in memoria. Il conteggio nelle regioni, le mappe di calore e il calcolo della distanza sono semplici livelli aggiunti sopra questo ciclo.

Traccia i fotogrammi che leggi tu#

Passare un percorso o un URL gestisce automaticamente lo stato del tracker. Se i fotogrammi provengono da un decoder, una webcam o una telecamera RTSP di tua scelta, passa persist=True affinché ogni chiamata continui la stessa sequenza (la documentazione della modalità di predizione elenca tutti i tipi di sorgente):

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 IDs

Il risultato è lo stesso che passando il percorso, perché persist=True ha mantenuto attivo un unico tracker per tutte le 62 chiamate.

Regola un tracker in base al tuo rilevatore#

Copia una configurazione inclusa nel pacchetto, abbassa le soglie non adatte al tuo rilevatore e passa il nuovo file:

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 IDs

Impostare le soglie appena sotto la confidenza mediana del rilevatore ha portato TrackTrack da 9 a 27 ID, un valore vicino al conteggio manuale. Le impostazioni condivise da tutti i tracker:

ImpostazioneValore predefinito di ByteTrackAumentala perAbbassala per
track_high_thresh0.25Ignorare le rilevazioni deboli nel primo abbinamentoTracciare con un rilevatore a bassa confidenza
new_track_thresh0.25Eliminare le tracce false di breve durataAvviare tracce per oggetti poco visibili
track_buffer30 fotogrammiResistere a occlusioni più prolungateLiberare prima gli ID degli oggetti usciti dalla scena
match_thresh0.8Abbinare con maggiore flessibilità (movimento rapido, riquadri instabili)Abbinare con maggiore rigore (folle)

Insidie#

Soglie superiori alla confidenza del rilevatore

Sintomo: molti meno ID rispetto agli oggetti, soprattutto con un modello piccolo. Soluzione: stampa la confidenza mediana dei rilevamenti (vedi la soluzione) e imposta new_track_thresh e track_high_thresh appena al di sotto di essa.

Dimenticare persist o condividerlo

Sintomo: gli ID si azzerano a ogni fotogramma quando chiami personalmente model.track(frame), oppure passano da un oggetto all'altro quando due telecamere alimentano un unico modello. Soluzione: passa persist=True per i fotogrammi consecutivi di un singolo flusso e assegna a ogni telecamera un'istanza del modello (oppure usa una sorgente .streams, che mantiene un tracker per flusso).

Sfarfallio degli ID sugli oggetti lenti

Sintomo: l'ID di un'auto parcheggiata cambia ogni pochi fotogrammi. Soluzione: il tracker avvia nuove tracce invece di abbinare quelle esistenti. Controlla prima la confidenza del rilevatore su quell'oggetto, poi aumenta match_thresh e track_buffer.

Provalo

Registra un video di 30–60 secondi del tuo ambito applicativo e conta manualmente gli oggetti di una classe. Esegui compare_trackers.py sul video, misura i punteggi di confidenza del rilevatore con lo script della soluzione e regola un file YAML del tracker in modo che il numero di ID si avvicini al conteggio manuale. Consegna una tabella con: tracker, ID univoci, conteggio manuale.

Criteri di completamento
La lezione è completata quando tutte le seguenti condizioni sono soddisfatte.
  • Hai i conteggi degli ID univoci per ByteTrack, BoT-SORT e TrackTrack sullo stesso video, affiancati a un conteggio manuale.

  • Sai spiegare il conteggio più basso facendo riferimento alle soglie del tracker e alla confidenza mediana del rilevatore.

  • Un file YAML del tracker regolato ha spostato il conteggio nella direzione che avevi previsto prima di eseguirlo.

Mostra la soluzione

Prima misura i punteggi di confidenza del rilevatore, poi imposta le soglie appena al di sotto:

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%

Per la clip della piazza, la tabella riporta: ByteTrack 32, BoT-SORT 33, TrackTrack 9, TrackTrack regolato 27, conteggio manuale circa 30. Solo il 17% delle rilevazioni supera new_track_thresh: 0.7 di TrackTrack, quindi abbassarlo a 0.35 (insieme a track_high_thresh: 0.3) è la correzione giusta; per questa telecamera fissa dall'alto, ByteTrack senza modifiche è la scelta più semplice.

Prossimi passi

Con gli ID stabili, la prossima lezione costruisce sopra di essi le pipeline di produzione più comuni: conteggi, zone, mappe di calore e velocità.

Accedi per salvare i progressi