Faza 04 · lecția 27
Urmărirea mai multor obiecte și memoria video
Scopul lecției: Urmărirea înseamnă detecție plus asociere. Detectați în fiecare cadru. Potriviți detecțiile din acest cadru cu traseele cadrului anterior după ID.
Versiunea curentă AlexBred.com: primele 100 de lecții ale programului în limba română.
Cuprinsul lecției
- Obiective de învățare
- Problema
- Conceptul
- Urmărirea prin detecție
- Filtrul Kalman într-un paragraf
- Algoritmul Hungarian
- Ideea-cheie a ByteTrack
- Urmărirea SAM 2 bazată pe memorie
- SAM 3.1 Object Multiplex
- Trei metrici de reținut
- Construiți
- Pasul 1: matricea de cost bazată pe IoU
- Pasul 2: tracker minimal în stil SORT
- Pasul 3: test cu traiectorii sintetice
- Pasul 4: metrica schimbărilor de ID
- Utilizați
- Livrați
- Exerciții
- Termeni-cheie
- Lecturi suplimentare
Urmărirea înseamnă detecție plus asociere. Detectați în fiecare cadru. Potriviți detecțiile din acest cadru cu traseele cadrului anterior după ID.
Tip: Construiți Limbaje: Python Cerințe prealabile: Faza 4 Lecția 06 (Detecție YOLO), Faza 4 Lecția 08 (Mask R-CNN), Faza 4 Lecția 24 (SAM 3) Timp: ~60 de minute
Obiective de învățare
- Deosebiți urmărirea prin detecție (tracking-by-detection) de urmărirea bazată pe interogări și numiți familiile de algoritmi (SORT, DeepSORT, ByteTrack, BoT-SORT, trackerul cu memorie SAM 2, SAM 3.1 Object Multiplex)
- Implementați de la zero atribuirea IoU + Hungarian pentru urmărirea clasică prin detecție
- Explicați banca de memorie a SAM 2 și de ce gestionează ocluzia mai bine decât asocierea bazată pe IoU
- Citiți cele trei metrici de urmărire (MOTA, IDF1, HOTA) și alegeți ce contează pentru un anumit caz de utilizare
Problema
Un detector indică unde se află obiectele într-un singur cadru. Un tracker indică ce detecție din cadrul t este același obiect cu o detecție din cadrul t-1. Fără aceasta, nu puteți număra obiectele care traversează o linie, urmări o minge printr-o ocluzie sau ști că „mașina nr. 4 este pe bandă de 8 secunde”.
Notă tehnică a traducerii: Potrivirea doar cu cadrul anterior este o simplificare introductivă. Trackerele pot păstra istoric, stări prezise, caracteristici de aspect, ferestre temporale sau interogări persistente; identitatea nu se decide exclusiv din două cadre consecutive.
Urmărirea este esențială pentru fiecare produs orientat spre video: analiză sportivă, supraveghere, conducere autonomă, analiză video medicală, monitorizarea faunei, numărarea logourilor. Componentele de bază sunt comune: un detector pe cadru, un model de mișcare (filtru Kalman sau ceva mai bogat), un pas de asociere (algoritmul Hungarian pe IoU / cosinus / caracteristici învățate) și un ciclu de viață al traseului (naștere, actualizare, dispariție).
Anul 2026 a adus două tipare noi: urmărirea SAM 2 bazată pe memorie (memorie de caracteristici în loc de asociere prin model de mișcare) și SAM 3.1 Object Multiplex (memorie partajată pentru multe instanțe ale aceluiași concept). Această lecție parcurge mai întâi stiva clasică, apoi abordarea bazată pe memorie.
Notă tehnică a traducerii: SAM 2 a fost lansat în 2024 și este în principal un model promptabil de segmentare video, cu memorie pe sesiune pentru propagarea măștilor; nu este un înlocuitor direct, universal, pentru un tracker MOT cu detector, atribuire de ID și ciclu de viață al traseului. Modelul SAM 2 documentat folosește prompturi vizuale — puncte/clicuri, casete și măști — iar prompturile textuale de concept aparțin fluxurilor SAM 3. API-urile, prompturile și evaluarea măștilor trebuie verificate pentru checkpointul concret.
Conceptul
Urmărirea prin detecție
Fiecare tracker pe care îl veți întâlni în 2026 este o variație a acestei bucle. Diferențele:
- SORT (2016): filtru Kalman + Hungarian pe IoU. Simplu, rapid, fără model de aspect.
- DeepSORT (2017): SORT + o caracteristică de aspect bazată pe CNN pentru fiecare traseu (reprezentare vectorială ReID). Gestionează mai bine traversările.
- ByteTrack (2021): asociază detecțiile cu încredere scăzută ca a doua etapă; nu necesită caracteristici de aspect, dar are performanță de vârf pe MOT17.
- BoT-SORT (2022): Byte + compensarea mișcării camerei + ReID.
- StrongSORT / OC-SORT — descendenți ByteTrack cu mișcare și aspect mai bune.
Notă tehnică a traducerii: Bucla detector–asociere descrie familia tracking-by-detection, nu fiecare tracker modern; trackerele end-to-end bazate pe interogări sau pe Transformere pot avea mecanisme diferite. StrongSORT și OC-SORT nu sunt în mod general „descendenți ByteTrack”, ci linii de dezvoltare distincte ale tracking-by-detection. Rezultatele ByteTrack pe MOT17 sunt cele raportate de lucrare în configurațiile ei, nu o poziție permanentă pe toate benchmarkurile și detectoarele.
Filtrul Kalman într-un paragraf
Un filtru Kalman menține pentru fiecare traseu o stare (x, y, w, h, dx, dy, dw, dh) cu o covarianță. La fiecare cadru, prezice starea cu un model de viteză constantă, apoi o actualizează cu detecția potrivită. Actualizarea acordă mai multă încredere detecției când incertitudinea predicției este mare. Aceasta oferă traiectorii netede și capacitatea de a continua un traseu printr-o ocluzie scurtă (1–5 cadre).
Fiecare tracker clasic folosește un filtru Kalman în etapa de predicție a mișcării.
Notă tehnică a traducerii: Un filtru Kalman și modelul de viteză constantă sunt alegeri frecvente, nu cerințe ale fiecărui tracker clasic. Durata ocluziei recuperabile depinde de frecvența cadrelor, dinamica obiectului, detector, pragurile de asociere și mecanismul ReID; un filtru nu poate restaura singur o identitate după o pierdere ambiguă.
Algoritmul Hungarian
Dată o matrice de cost M x N (trasee x detecții), găsiți atribuirea unu-la-unu care minimizează costul total. Costul este de obicei 1 - IoU(track_bbox, detection_bbox) sau similitudinea cosinus negativă a caracteristicilor de aspect. Timpul de rulare este O((M+N)^3); pentru M, N de până la aproximativ 1000 este suficient de rapid în Python prin scipy.optimize.linear_sum_assignment.
Notă tehnică a traducerii: Complexitatea și timpul efectiv depind de implementare, forma matricei, praguri și hardware; „suficient de rapid” la 1000 de obiecte nu este o garanție de latență pentru un flux video. Confirmați costul și strategia de gating pentru numărul real de obiecte din scenă.
Ideea-cheie a ByteTrack
Trackerele standard elimină detecțiile cu încredere scăzută (< 0,5). ByteTrack le păstrează ca candidați ai etapei a doua: după potrivirea traseelor cu detecțiile cu încredere mare, traseele neasociate încearcă să se potrivească cu detecțiile cu încredere mică, cu un prag IoU puțin mai permisiv. Recuperează ocluziile scurte, schimbările de ID în apropierea mulțimilor.
Urmărirea SAM 2 bazată pe memorie
SAM 2 gestionează video păstrând o bancă de memorie cu caracteristici spațio-temporale pe instanță. Dat un prompt (clic, casetă, text) într-un cadru, el codifică instanța în memorie. În cadrele următoare, memoria primește cross-attention față de caracteristicile noului cadru, iar decodorul produce o mască pentru aceeași instanță în noul cadru.
Fără filtru Kalman, fără atribuire Hungarian. Asocierea este implicită în operația de atenție asupra memoriei.
Avantaje:
- Robust la ocluzii mari (memoria poartă identitatea instanței pe multe cadre).
- Vocabular deschis când este combinat cu prompturile textuale SAM 3.
- Funcționează fără un model de mișcare separat.
Dezavantaje:
- Mai lent decât ByteTrack pentru urmărirea multor obiecte.
- Banca de memorie crește; limitează fereastra de context.
Notă tehnică a traducerii: Descrierea de mai sus simplifică SAM 2: documentația lui descrie segmentare video promptabilă și propagarea obiectelor prin memorie, nu API-ul generic
processor.track()și nici un MOT standard cu casete. SAM 2 nu primește prompt text generic în interfața sa de bază; SAM 3 introduce prompturi de concept și text. Comparațiile de viteză, ocluzie și fereastră de context necesită același video, hardware, număr de obiecte și metrică.
SAM 3.1 Object Multiplex
Urmărirea SAM 2 / SAM 3 anterioară păstrează o bancă de memorie separată pe instanță. Pentru 50 de obiecte, 50 de bănci de memorie. Object Multiplex (martie 2026) le comprimă într-o singură memorie partajată cu tokenuri de interogare pe instanță. Costul scalează subliniar cu numărul de instanțe.
Multiplex este noua valoare implicită pentru urmărirea mulțimilor în 2026: mulțimi la concerte, lucrători în depozite, intersecții cu trafic.
Notă tehnică a traducerii: Postarea oficială Meta din 27 martie 2026 verifică lansarea SAM 3.1 Object Multiplex și afirmă urmărirea a până la 16 obiecte într-o singură trecere, precum și o măsurătoare de throughput pe un H100. Viteza reală depinde de numărul de obiecte, videoclip, rezoluție, model și hardware. Postarea nu trebuie extinsă tacit la detaliile implementării din original — „memorie partajată”, „tokenuri de interogare pe instanță” și scalare subliniară — fără a consulta checkpointul, codul și lucrarea versiunii exacte. „Valoarea implicită” pentru mulțimi depinde de acuratețe, latență, hardware, licență și fluxul de integrare.
Trei metrici de reținut
- MOTA (Multi-Object Tracking Accuracy) — 1 - (FN + FP + schimbări de ID) / GT. Ponderată după tipul erorii; o singură metrică ce combină eșecurile de detecție și asociere.
- IDF1 (ID F1) — media armonică a preciziei și recall-ului ID. Se concentrează în special pe cât de bine își păstrează fiecare traseu de adevăr de referință ID-ul în timp. Mai bună decât MOTA pentru sarcini sensibile la schimbări de ID.
- HOTA (Higher Order Tracking Accuracy) — se descompune în acuratețea detecției (DetA) și acuratețea asocierii (AssA). Standardul comunității din 2020; cel mai cuprinzător.
Pentru supraveghere (cine este cine): raportați IDF1. Pentru analiză sportivă (numărarea paselor): HOTA. Pentru comparație academică generală: HOTA.
Notă tehnică a traducerii: Nicio metrică nu este suficientă singură pentru toate deciziile. MOTA numără FP, FN și schimbări de ID față de instanțele GT și poate ascunde erori de asociere; IDF1 se bazează pe o potrivire globală a identităților în timp; HOTA combină DetA și AssA peste praguri de asociere. Alegerea trebuie să urmeze riscul operațional, setul de date și protocolul; „standardul comunității” și recomandările pe domenii nu înlocuiesc raportarea mai multor metrici.
Construiți
Pasul 1: matricea de cost bazată pe IoU
import numpy as np
def bbox_iou(a, b):
"""
a, b: (N, 4) arrays of [x1, y1, x2, y2].
Returns (N_a, N_b) IoU matrix.
"""
ax1, ay1, ax2, ay2 = a[:, 0], a[:, 1], a[:, 2], a[:, 3]
bx1, by1, bx2, by2 = b[:, 0], b[:, 1], b[:, 2], b[:, 3]
inter_x1 = np.maximum(ax1[:, None], bx1[None, :])
inter_y1 = np.maximum(ay1[:, None], by1[None, :])
inter_x2 = np.minimum(ax2[:, None], bx2[None, :])
inter_y2 = np.minimum(ay2[:, None], by2[None, :])
inter = np.clip(inter_x2 - inter_x1, 0, None) * np.clip(inter_y2 - inter_y1, 0, None)
area_a = (ax2 - ax1) * (ay2 - ay1)
area_b = (bx2 - bx1) * (by2 - by1)
union = area_a[:, None] + area_b[None, :] - inter
return inter / np.clip(union, 1e-8, None)
Pasul 2: tracker minimal în stil SORT
Filtrul Kalman cu viteză constantă este omis pentru concizie — folosim aici o asociere IoU simplă; în producție predicția Kalman este esențială. Pachetul Python sort oferă versiunea completă.
from scipy.optimize import linear_sum_assignment
class Track:
def __init__(self, tid, bbox, frame):
self.id = tid
self.bbox = bbox
self.last_frame = frame
self.hits = 1
def update(self, bbox, frame):
self.bbox = bbox
self.last_frame = frame
self.hits += 1
class SimpleTracker:
def __init__(self, iou_threshold=0.3, max_age=5):
self.tracks = []
self.next_id = 1
self.iou_threshold = iou_threshold
self.max_age = max_age
def step(self, detections, frame):
if not self.tracks:
for d in detections:
self.tracks.append(Track(self.next_id, d, frame))
self.next_id += 1
return [(t.id, t.bbox) for t in self.tracks]
track_boxes = np.array([t.bbox for t in self.tracks])
det_boxes = np.array(detections) if len(detections) else np.empty((0, 4))
iou = bbox_iou(track_boxes, det_boxes) if len(det_boxes) else np.zeros((len(track_boxes), 0))
cost = 1 - iou
cost[iou < self.iou_threshold] = 1e6
matched_track = set()
matched_det = set()
if cost.size > 0:
row, col = linear_sum_assignment(cost)
for r, c in zip(row, col):
if cost[r, c] < 1.0:
self.tracks[r].update(det_boxes[c], frame)
matched_track.add(r); matched_det.add(c)
for i, d in enumerate(det_boxes):
if i not in matched_det:
self.tracks.append(Track(self.next_id, d, frame))
self.next_id += 1
self.tracks = [t for t in self.tracks if frame - t.last_frame <= self.max_age]
return [(t.id, t.bbox) for t in self.tracks]
60 de linii. Primește detecții pe cadru și returnează ID-uri de traseu pe cadru. Sistemele reale adaugă predicția Kalman, re-potrivirea din etapa a doua a ByteTrack și caracteristici de aspect.
Notă tehnică a traducerii:
SimpleTrackereste o bază IoU, nu implementarea SORT completă: nu are stare Kalman, predicție, ReID, detecții cu scor sau re-asocierea ByteTrack. El presupune casete valide[x1, y1, x2, y2]în același sistem de coordonate și nu validează formatul acestora. Traseele neasociate sunt păstrate cu ultima casetă observată până lamax_age; ele nu sunt propagate fizic prin ocluzie. Tratați-o ca demonstrație a atribuirii, nu ca tracker de producție.
Pasul 3: test cu traiectorii sintetice
def synthetic_frames(num_frames=20, num_objects=3, H=240, W=320, seed=0):
rng = np.random.default_rng(seed)
starts = rng.uniform(20, 200, size=(num_objects, 2))
velocities = rng.uniform(-5, 5, size=(num_objects, 2))
frames = []
for f in range(num_frames):
dets = []
for i in range(num_objects):
cx, cy = starts[i] + f * velocities[i]
dets.append([cx - 10, cy - 10, cx + 10, cy + 10])
frames.append(dets)
return frames
tracker = SimpleTracker()
for f, dets in enumerate(synthetic_frames()):
tracks = tracker.step(dets, f)
Trei obiecte care se mișcă în linii drepte ar trebui să își păstreze ID-urile de-a lungul tuturor celor 20 de cadre.
Notă tehnică a traducerii: Testul produce detecții perfecte, cu mișcare liniară și fără ocluzii, scoruri, zgomot sau camere în mișcare. El verifică mecanica exemplului, nu calitatea unui tracker pe video real.
Pasul 4: metrica schimbărilor de ID
def count_id_switches(tracks_per_frame, gt_per_frame):
"""
tracks_per_frame: list of list of (track_id, bbox)
gt_per_frame: list of list of (gt_id, bbox)
Returns number of ID switches.
"""
prev_assignment = {}
switches = 0
for tracks, gts in zip(tracks_per_frame, gt_per_frame):
if not tracks or not gts:
continue
t_boxes = np.array([b for _, b in tracks])
g_boxes = np.array([b for _, b in gts])
iou = bbox_iou(g_boxes, t_boxes)
for g_idx, (gt_id, _) in enumerate(gts):
j = iou[g_idx].argmax()
if iou[g_idx, j] > 0.5:
t_id = tracks[j][0]
if gt_id in prev_assignment and prev_assignment[gt_id] != t_id:
switches += 1
prev_assignment[gt_id] = t_id
return switches
Aceasta este o metrică simplificată, apropiată de IDF1: numără de câte ori un obiect de adevăr de referință își schimbă ID-ul traseului prezis atribuit. Instrumentele reale pentru MOTA / IDF1 / HOTA se află în py-motmetrics și TrackEval.
Notă tehnică a traducerii: Această funcție nu este IDF1, MOTA sau HOTA: alege independent pentru fiecare GT caseta cu IoU maxim, nu impune potrivire unu-la-unu și poate ignora cadrele fără potriviri. Folosiți TrackEval sau un evaluator compatibil cu benchmarkul pentru metrici publicabile.
Utilizați
Trackere de producție în 2026:
ultralytics— YOLOv8 + ByteTrack / BoT-SORT integrate.results = model.track(source, tracker="bytetrack.yaml"). Valoarea implicită.supervision(Roboflow) — învelișuri ByteTrack plus utilitare de adnotare.- SAM 2 / SAM 3.1 — urmărire bazată pe memorie prin
processor.track(). - Stivă proprie: detector (YOLOv8 / RT-DETR) +
sort-tracker/OC-SORT/StrongSORT.
Alegerea:
- Pietoni / mașini / cutii la peste 30 fps: ByteTrack cu ultralytics.
- Multe instanțe ale unei clase într-o mulțime: SAM 3.1 Object Multiplex.
- Ocluzii puternice cu aspect identificabil: DeepSORT / StrongSORT (caracteristici ReID).
- Sport / interacțiuni complexe: BoT-SORT sau trackere învățate (MOTRv3).
Notă tehnică a traducerii: În documentația Ultralytics curentă, BoT-SORT este trackerul implicit, iar ByteTrack se selectează explicit prin
tracker="bytetrack.yaml"; formularea „valoarea implicită” pentru ByteTrack nu este corectă. La procesarea manuală cadru-cu-cadru, păstrați starea prinpersist=True; în caz contrar, ID-urile nu trebuie presupuse persistente între apeluri. API-ulprocessor.track()nu este o interfață generică verificată pentru SAM 2 sau SAM 3.1 întransformers: SAM 2 folosește clase și pași de sesiune video specifici. SAM 3.1 nu are integrare în Hugging Face Transformers; utilizați codul oficial SAM 3 și predictorul video al versiunii corespunzătoare. Recomandările de alegere depind de detector, densitate, frecvență de cadre, hardware, metrică și cerințele de latență, nu numai de categoria scenei.
Livrați
Această lecție produce:
outputs/prompt-tracker-picker.md— alege SORT / ByteTrack / BoT-SORT / SAM 2 / SAM 3.1 după tipul scenei, tiparele de ocluzie și bugetul de latență.outputs/skill-mot-evaluator.md— scrie un cadru complet de evaluare pentru MOTA / IDF1 / HOTA față de traseele de adevăr de referință.
Exerciții
- (Ușor) Rulați trackerul sintetic de mai sus cu 3, 10 și 30 de obiecte. Raportați numărul schimbărilor de ID în fiecare caz. Identificați unde asocierea simplă doar cu IoU începe să eșueze.
- (Mediu) Adăugați un pas de predicție Kalman cu viteză constantă înainte de asociere. Arătați că ocluziile scurte (2–3 cadre) nu mai cauzează schimbări de ID.
- (Dificil) Integrați trackerul SAM 2 bazat pe memorie (prin
transformers) ca backend alternativ de urmărire. Rulați atât SimpleTracker, cât și SAM 2 pe un clip de 30 de secunde cu o mulțime și comparați numărul schimbărilor de ID, etichetând manual ID-urile de adevăr de referință pentru 5 persoane importante.
Notă tehnică a traducerii: În exercițiul 2, Kalman poate îmbunătăți predicția poziției, dar nu garantează absența schimbărilor de ID fără detecții de revenire, gating și asociere potrivite; modelați explicit ocluziile, reapariția și schimbările de traseu. În exercițiul 3, SAM 2 prin
transformersnu este o înlocuire directă pentruSimpleTracker: trebuie folosite API-ul real de sesiune/procesare video și modelul, iar măștile propagate trebuie convertite într-un protocol de ID și evaluare comparabil cu adevărul de referință.
Termeni-cheie
| Termen | Ce spun oamenii | Ce înseamnă de fapt |
|---|---|---|
| Urmărire prin detecție | „Detectați, apoi asociați” | Detector pe cadru + atribuire Hungarian pe IoU / aspect |
| Filtru Kalman | „Predicție de mișcare” | Dinamică liniară + covarianță pentru predicții de traseu netede și gestionarea ocluziei |
| Algoritmul Hungarian | „Atribuire optimă” | Rezolvă problema de potrivire bipartită cu cost minim; scipy.optimize.linear_sum_assignment |
| ByteTrack | „A doua trecere cu încredere scăzută” | Re-potrivește traseele neasociate cu detecțiile de încredere scăzută pentru a recupera ocluziile scurte |
| DeepSORT | „SORT + aspect” | Adaugă o caracteristică ReID pentru potrivirea între cadre; mai bun pentru păstrarea ID-ului |
| Bancă de memorie | „Trucul SAM 2” | Caracteristici spațio-temporale pe instanță păstrate între cadre; cross-attention înlocuiește asocierea explicită |
| Object Multiplex | „Memorie partajată SAM 3.1” | O singură memorie partajată cu interogări pe instanță pentru urmărire rapidă a multor obiecte |
| HOTA | „Metrică modernă de urmărire” | Se descompune în acuratețea detecției și a asocierii; standard comunitar |
Lecturi suplimentare
- SORT (Bewley et al., 2016) — lucrarea minimală despre urmărirea prin detecție
- DeepSORT (Wojke et al., 2017) — adaugă caracteristica de aspect
- ByteTrack (Zhang et al., 2022) — a doua trecere cu încredere scăzută
- BoT-SORT (Aharon et al., 2022) — compensarea mișcării camerei
- HOTA (Luiten et al., 2020) — metrica de urmărire descompusă
- Segmentare video SAM 2 (Meta, 2024) — trackerul bazat pe memorie
- SAM 3.1 Object Multiplex (Meta, martie 2026)
Sursă: Originalul în limba engleză
Navigare: ← Lecția 04.26 — Adâncimea monoculară și estimarea geometriei · Faza 4 — Viziune computerizată · Lecția 04.28 — Modele ale lumii și difuzia video → · Catalog complet