Фаза 04 · урок 27
Отслеживание нескольких объектов и видеопамять
Цель урока: Детектор сообщает, где находятся объекты в одном кадре. Трекер сообщает, какое обнаружение в кадре t соответствует тому же объекту, что и обнаружение в кадре t-1 . Без этого нельзя считать объекты, пересекающие линию, следить за мячом…
Текущий релиз AlexBred.com: первые 100 уроков русскоязычной программы.
Содержание урока
- Цели обучения
- Проблема
- Концепция
- Отслеживание через обнаружение
- Фильтр Калмана в одном абзаце
- Венгерский алгоритм
- Ключевая идея ByteTrack
- Отслеживание SAM 2 на основе памяти
- SAM 3.1 Object Multiplex
- Три метрики, которые нужно знать
- Соберите
- Шаг 1: матрица стоимостей на основе IoU
- Шаг 2: минимальный трекер в стиле SORT
- Шаг 3: тест синтетических траекторий
- Шаг 4: метрика переключений ID
- Используйте
- Поставьте в продакшен
- Упражнения
- Ключевые термины
- Дополнительные материалы
Отслеживание — это обнаружение плюс сопоставление. Обнаруживайте объекты в каждом кадре. Сопоставляйте обнаружения текущего кадра с треками прошлого кадра по ID.
Тип: Соберите Языки: Python Предварительные требования: Фаза 4, урок 06 (обнаружение YOLO), фаза 4, урок 08 (Mask R-CNN), фаза 4, урок 24 (SAM 3) Время: ~60 минут
Цели обучения
- Различать отслеживание через обнаружение (tracking-by-detection) и отслеживание на основе запросов, а также называть семейства алгоритмов (SORT, DeepSORT, ByteTrack, BoT-SORT, трекер памяти SAM 2, SAM 3.1 Object Multiplex)
- Реализовать с нуля IoU + венгерское назначение для классического отслеживания через обнаружение
- Объяснить банк памяти SAM 2 и то, почему он лучше справляется с окклюзиями, чем сопоставление на основе IoU
- Читать три метрики отслеживания (MOTA, IDF1, HOTA) и выбирать важную для конкретного сценария
Проблема
Детектор сообщает, где находятся объекты в одном кадре. Трекер сообщает, какое обнаружение в кадре t соответствует тому же объекту, что и обнаружение в кадре t-1. Без этого нельзя считать объекты, пересекающие линию, следить за мячом во время окклюзии или знать, что «автомобиль № 4 находится в полосе уже 8 секунд».
Отслеживание необходимо каждому продукту, работающему с видео: спортивной аналитике, видеонаблюдению, автономному вождению, анализу медицинских видео, мониторингу дикой природы, подсчёту словесных знаков. Основные строительные блоки общие: детектор для каждого кадра, модель движения (фильтр Калмана или нечто более сложное), шаг сопоставления (венгерский алгоритм по IoU / косинусной мере / обученным признакам) и жизненный цикл трека (рождение, обновление, завершение).
2026 год принёс два новых паттерна: отслеживание SAM 2 на основе памяти (память признаков вместо сопоставления моделью движения) и SAM 3.1 Object Multiplex (общая память для многих экземпляров одного концепта). В этом уроке сначала разобран классический стек, а затем подход на основе памяти.
Концепция
Отслеживание через обнаружение
Каждый трекер, с которым вы столкнётесь в 2026 году, — вариация этого цикла. Различия таковы:
- SORT (2016): фильтр Калмана + IoU + венгерский алгоритм. Прост, быстр, не имеет модели внешнего вида.
- DeepSORT (2017): SORT + признак внешнего вида на основе CNN для каждого трека (ReID-эмбеддинг). Лучше обрабатывает пересечения.
- ByteTrack (2021): на втором этапе сопоставляет обнаружения с низкой уверенностью; признаки внешнего вида не требуются, но это лидер на MOT17.
- BoT-SORT (2022): Byte + компенсация движения камеры + ReID.
- StrongSORT / OC-SORT — потомки ByteTrack с улучшенным движением и внешним видом.
Фильтр Калмана в одном абзаце
Фильтр Калмана поддерживает для каждого трека состояние (x, y, w, h, dx, dy, dw, dh) с ковариацией. В каждом кадре он предсказывает состояние с помощью модели постоянной скорости, затем обновляет его сопоставленным обнаружением. Когда неопределённость предсказания высока, обновление больше доверяет обнаружению. Это даёт гладкие траектории и возможность продолжать трек во время короткой окклюзии (1–5 кадров).
Каждый классический трекер использует фильтр Калмана на шаге предсказания движения.
Венгерский алгоритм
Для матрицы стоимостей M x N (треки × обнаружения) найдите взаимно однозначное назначение, минимизирующее суммарную стоимость. Обычно стоимость равна 1 - IoU(track_bbox, detection_bbox) или отрицательному косинусному сходству признаков внешнего вида. Время работы — O((M+N)^3); при M, N до ~1000 алгоритм достаточно быстр в Python через scipy.optimize.linear_sum_assignment.
Ключевая идея ByteTrack
Стандартные трекеры отбрасывают обнаружения с низкой уверенностью (< 0.5). ByteTrack сохраняет их как кандидатов второго этапа: после сопоставления треков с обнаружениями высокой уверенности несопоставленные треки пытаются сопоставиться с обнаружениями низкой уверенности при немного более мягком пороге IoU. Это восстанавливает короткие окклюзии и переключения ID рядом с толпами.
Отслеживание SAM 2 на основе памяти
SAM 2 обрабатывает видео, сохраняя банк памяти пространственно-временных признаков для каждого экземпляра. Получив запрос (щелчок, рамку, текст) на одном кадре, он кодирует экземпляр в память. На последующих кадрах память участвует в cross-attention с признаками нового кадра, а декодер создаёт маску того же экземпляра в новом кадре.
Нет ни фильтра Калмана, ни венгерского назначения. Сопоставление неявно выполняется в операции внимания к памяти.
Плюсы:
- Устойчивость к большим окклюзиям (память переносит идентичность экземпляра через множество кадров).
- Открытый словарь в сочетании с текстовыми запросами SAM 3.
- Работа без отдельной модели движения.
Минусы:
- Медленнее ByteTrack при отслеживании множества объектов.
- Банк памяти растёт и ограничивает окно контекста.
SAM 3.1 Object Multiplex
Предыдущее отслеживание SAM 2 / SAM 3 хранит отдельный банк памяти для каждого экземпляра. Для 50 объектов — 50 банков памяти. Object Multiplex (март 2026 года) объединяет их в одну общую память с токенами запросов для каждого экземпляра. Стоимость масштабируется сублинейно относительно числа экземпляров.
Multiplex — новый вариант по умолчанию для отслеживания толп в 2026 году: толпы на концертах, работники склада, дорожные перекрёстки.
Три метрики, которые нужно знать
- MOTA (Multi-Object Tracking Accuracy) — 1 - (FN + FP + переключения ID) / GT. Взвешивается по типу ошибки; одна метрика, смешивающая ошибки обнаружения и сопоставления.
- IDF1 (ID F1) — гармоническое среднее точности и полноты ID. Фокусируется на том, насколько хорошо каждый трек истинных данных сохраняет свой ID во времени. Лучше MOTA для задач, чувствительных к переключениям ID.
- HOTA (Higher Order Tracking Accuracy) — раскладывается на точность обнаружения (DetA) и точность сопоставления (AssA). Стандарт сообщества с 2020 года; наиболее полная метрика.
Для видеонаблюдения (кто есть кто) сообщайте IDF1. Для спортивной аналитики (подсчёт передач) — HOTA. Для общего академического сравнения — HOTA.
Соберите
Шаг 1: матрица стоимостей на основе 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)
Шаг 2: минимальный трекер в стиле SORT
Полный фильтр Калмана с постоянной скоростью для краткости опущен — здесь используется простое сопоставление по IoU; в продакшене предсказание Калмана необходимо. Полную версию предоставляет Python-пакет sort.
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 строк. Получает обнаружения по кадрам, возвращает ID треков по кадрам. В реальные системы добавляются предсказание Калмана, повторное сопоставление второго этапа ByteTrack и признаки внешнего вида.
Шаг 3: тест синтетических траекторий
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)
Три объекта, движущиеся по прямым, должны сохранять свои ID на всех 20 кадрах.
Шаг 4: метрика переключений 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
Это упрощённая метрика, близкая к IDF1: она считает, сколько раз объект истинных данных меняет назначенный ему ID предсказанного трека. Настоящие инструменты MOTA / IDF1 / HOTA находятся в py-motmetrics и TrackEval.
Используйте
Продакшен-трекеры в 2026 году:
ultralytics— встроенные YOLOv8 + ByteTrack / BoT-SORT.results = model.track(source, tracker="bytetrack.yaml"). Вариант по умолчанию.supervision(Roboflow) — обёртки ByteTrack и утилиты аннотирования.- SAM 2 / SAM 3.1 — отслеживание на основе памяти через
processor.track(). - Пользовательский стек: детектор (YOLOv8 / RT-DETR) +
sort-tracker/OC-SORT/StrongSORT.
Выбор:
- Пешеходы / автомобили / коробки при 30+ fps: ByteTrack с ultralytics.
- Много экземпляров одного класса в толпе: SAM 3.1 Object Multiplex.
- Тяжёлые окклюзии при различимом внешнем виде: DeepSORT / StrongSORT (ReID-признаки).
- Спорт / сложные взаимодействия: BoT-SORT или обученные трекеры (MOTRv3).
Поставьте в продакшен
Этот урок создаёт:
outputs/prompt-tracker-picker.md— выбирает SORT / ByteTrack / BoT-SORT / SAM 2 / SAM 3.1 с учётом типа сцены, паттернов окклюзий и бюджета задержки.outputs/skill-mot-evaluator.md— пишет полный набор оценки MOTA / IDF1 / HOTA по трекам истинных данных.
Упражнения
- (Легко) Запустите приведённый выше синтетический трекер с 3, 10 и 30 объектами. Сообщите число переключений ID в каждом случае. Определите, где начинает давать сбои простое сопоставление только по IoU.
- (Средне) Добавьте шаг предсказания фильтром Калмана с постоянной скоростью перед сопоставлением. Покажите, что короткие окклюзии (2–3 кадра) больше не вызывают переключений ID.
- (Сложно) Интегрируйте трекер SAM 2 на основе памяти (через
transformers) как альтернативный бэкенд трекера. Запустите и SimpleTracker, и SAM 2 на 30-секундном клипе толпы и сравните числа переключений ID, вручную разметив истинные ID для 5 заметных людей.
Ключевые термины
| Термин | Как обычно говорят | Что это на самом деле означает |
|---|---|---|
| Отслеживание через обнаружение | «Сначала обнаружить, затем сопоставить» | Детектор по кадрам + венгерское назначение по IoU / внешнему виду |
| Фильтр Калмана | «Предсказание движения» | Линейная динамика + ковариация для гладких предсказаний треков и обработки окклюзий |
| Венгерский алгоритм | «Оптимальное назначение» | Решает задачу двудольного сопоставления с минимальной стоимостью; scipy.optimize.linear_sum_assignment |
| ByteTrack | «Второй проход с низкой уверенностью» | Повторно сопоставляет несопоставленные треки с обнаружениями низкой уверенности, чтобы восстановить короткие окклюзии |
| DeepSORT | «SORT + внешний вид» | Добавляет ReID-признак для сопоставления между кадрами; лучше сохраняет ID |
| Банк памяти | «Приём SAM 2» | Пространственно-временные признаки экземпляра, сохраняемые между кадрами; cross-attention заменяет явное сопоставление |
| Object Multiplex | «Общая память SAM 3.1» | Единая общая память с запросами для каждого экземпляра для быстрого отслеживания множества объектов |
| HOTA | «Современная метрика отслеживания» | Раскладывается на точность обнаружения и сопоставления; стандарт сообщества |
Дополнительные материалы
- SORT (Bewley et al., 2016) — минимальная статья об отслеживании через обнаружение
- DeepSORT (Wojke et al., 2017) — добавляет признак внешнего вида
- ByteTrack (Zhang et al., 2022) — второй проход с низкой уверенностью
- BoT-SORT (Aharon et al., 2022) — компенсация движения камеры
- HOTA (Luiten et al., 2020) — декомпозированная метрика отслеживания
- Сегментация видео SAM 2 (Meta, 2024) — трекер на основе памяти
- SAM 3.1 Object Multiplex (Meta, март 2026 года)
Источник: Multi-Object Tracking & Video Memory 04.26 — Монокулярная оценка глубины · Фаза 04 — Компьютерное зрение · 04.28 — Мировые модели и диффузия видео · Полный каталог