Запуск инференса на видео
Запускай YOLO26 на видеофайлах и с камер в реальном времени с ограниченным потреблением памяти, отслеживай объекты, чтобы посчитать каждый только один раз, и проверяй, успевает ли модель обрабатывать кадры с частотой источника.
Большинство внедрённых систем компьютерного зрения анализируют видео: камеры над конвейерами, у дверей и на дорогах. В видео есть две проблемы, которых нет у отдельных изображений. Память: длинную запись нельзя целиком хранить в оперативной памяти. Идентификация: детектор видит одного и того же человека в 60 кадрах и сообщает о 60 людях.
В этом уроке ты будешь обрабатывать видео покадрово с помощью режима Predict, добавишь отслеживание объектов, чтобы считать каждого человека один раз, напишешь собственный цикл обработки с камеры и измеришь, успевает ли модель обрабатывать кадры.
Практические занятия
Пример: предсказание на видеофайле#
Видео обрабатывается в том же режиме Predict, что и изображения. В этом 62-кадровом клипе люди пересекают атриум:
yolo predict model=yolo26n.pt source=https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4video 1/1 (frame 1/62) solutions_ci_demo.mp4: 384x640 22 persons, 27.3ms
...
video 1/1 (frame 62/62) solutions_ci_demo.mp4: 384x640 22 persons, 54.8ms
Results saved to runs/detect/predictframe 1/62: Ultralytics декодирует видео и обрабатывает каждый кадр как изображение.22 persons: детекции в этом кадре. Те же прохожие снова учитываются в каждом кадре.27.3ms...54.8ms: время обработки каждого кадра меняется в зависимости от нагрузки на компьютер.
Видео с аннотациями сохранено в runs/detect/predict/solutions_ci_demo.mp4. Твоя модель работает так же: замени yolo26n.pt на runs/detect/pills_v1/weights/best.pt.
Обработка длинных потоков и трансляций в реальном времени#
Если код выполняет действия с детекциями, обрабатывай поток в цикле. На каждой итерации возвращается Results одного кадра, а затем кадр удаляется:
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
source = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
frames, people = 0, 0
for result in model(source, stream=True, classes=[0], verbose=False): # one Results object per frame
frames += 1
people += len(result.boxes)
print(f"{frames} frames, {people / frames:.1f} people per frame")62 frames, 22.2 people per frameТот же цикл работает с индексом веб-камеры (source=0) или URL камеры, например rtsp://camera.local/stream, и выполняется, пока поток не завершится или ты его не остановишь. Добавь vid_stride=2, чтобы обрабатывать каждый второй кадр. Руководство по инференсу в реальном времени с Streamlit показывает, как обернуть этот цикл в приложение с браузерным интерфейсом.
Пример: считай каждого человека один раз#
«22 человека в кадре» — не та цифра, которая нужна; нужна «сколько человек прошло мимо». Многообъектный трекинг связывает рамки между кадрами, а режим Track присваивает каждому объекту идентификатор в boxes.id:
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
source = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
seen = set()
for result in model.track(source, stream=True, persist=True, classes=[0], tracker="bytetrack.yaml", verbose=False):
if result.boxes.is_track:
seen.update(result.boxes.id.int().tolist())
print(f"{len(seen)} unique people tracked")32 unique people trackedis_track — это False для кадров до подтверждения трека, когда boxes.id равно None. Используй идентификаторы для подсчёта, построения траекторий или логики вроде «этот объект находится здесь уже 3 секунды».

| Трекер | Скорость | Надёжность |
|---|---|---|
bytetrack.yaml | Быстрее, проще | Чаще теряет идентификаторы, когда объекты ненадолго исчезают |
botsort.yaml | Медленнее | Лучше сохраняет идентификаторы при движении камеры (компенсация движения; ReID по внешнему виду включается отдельно через with_reid) |
Не указывай tracker, и Ultralytics использует tracktrack.yaml — текущий вариант по умолчанию; в режиме Track также доступны ocsort.yaml, deepocsort.yaml и fasttrack.yaml. Выбор и настройка трекеров, а также создание на их основе систем подсчёта объектов, тепловых карт и оценки скорости рассматриваются в руководстве «Отслеживание объектов с ByteTrack, BoT-SORT и TrackTrack».
Пример: собственный цикл обработки с камеры#
Реальным приложениям часто нужно самостоятельно считывать кадры — чтобы изменить размер, обрезать их, добавить временную метку или предоставить доступ к камере другому коду — и передавать каждый кадр модели. В таком случае persist=True поддерживает работу трекера между вызовами:
import cv2
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
cap = cv2.VideoCapture("solutions_ci_demo.mp4") # saved locally by the commands above; or 0, or an rtsp:// URL
seen = set()
while cap.isOpened():
ok, frame = cap.read()
if not ok:
break
result = model.track(frame, persist=True, classes=[0], tracker="bytetrack.yaml", verbose=False)[0]
if result.boxes.is_track:
seen.update(result.boxes.id.int().tolist())
cap.release()
print(f"{len(seen)} unique people, highest ID {max(seen)}")32 unique people, highest ID 67Столько же людей, сколько в track.py: 32. Обрати внимание: наибольший идентификатор — 67, а не 32: трекер присваивает идентификаторы и предварительным трекам, которые так и не подтверждаются, поэтому в нумерации есть пропуски.
Успевай за источником#
Камера с частотой 30 FPS передаёт кадр каждые 33 мс, а эффективная частота ограничена самым медленным этапом: декодированием, инференсом или записью. На нашем ноутбуке с CPU обработка yolo26n занимала от 26 до 46 мс на кадр размером 384×640 в разных запусках, в зависимости от нагрузки на компьютер: это равно бюджету или превышает его, запаса нет. Если твоя система не успевает, попробуй следующие способы по порядку:
| Способ | Эффект |
|---|---|
Модель поменьше (n вместо s) | Часто ускоряет в 2–3 раза |
Уменьши imgsz (480 вместо 640) | Меньше пикселей — меньше вычислений; в первую очередь страдает обнаружение мелких объектов |
vid_stride=2 | Сокращает объём работы вдвое; подходит для сцен с медленно движущимися объектами |
| GPU или оптимизированный экспорт | Самый большой прирост — движок TensorRT на NVIDIA или INT8; подробности — в следующем уроке |
Работа с несколькими камерами одновременно и связанная с этим многопоточность рассматриваются в руководстве «Инференс с несколькими потоками».
Избегай этих ошибок#
Симптом: при обработке длинной записи объём памяти растёт, пока процесс не завершится с ошибкой, или вызов для камеры в реальном времени никогда не возвращает результат. Причина: без этого параметра вызов Python собирает объект Results для каждого кадра, прежде чем вернуть результат. Решение: передай stream=True и используй генератор в цикле — он ничего не делает, пока ты не начнёшь его перебирать.
Симптом: в cv2_loop.py без persist=True количество упало до 27, и максимальный ID тоже оказался равен 27: ID начинались заново в каждом кадре, поэтому «уникальное» количество соответствовало лишь кадру с наибольшим числом объектов. Решение: передавай persist=True каждый раз, когда вызываешь track для очередного кадра.
Симптом: насчитано 67 человек при фактическом количестве 32. Причина: в ID есть пропуски из-за неподтверждённых треков. Решение: подсчитывай размер множества ID, как в track.py.
Трекер по умолчанию может меняться от версии к версии. Передавай tracker="bytetrack.yaml" (или выбранный тобой вариант), чтобы результаты подсчёта оставались сопоставимыми между версиями.
Показать решение
import sys
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
seen, times = set(), []
for result in model.track(sys.argv[1], stream=True, persist=True, tracker="bytetrack.yaml", verbose=False):
times.append(result.speed["inference"])
if result.boxes.is_track:
seen.update(result.boxes.id.int().tolist())
print(f"{len(seen)} unique objects, {sum(times) / len(times):.1f} ms inference per frame")Запусти его с python track_any.py your_video.mp4.
32 unique objects, 30.5 ms inference per frame (26-46 ms across runs on a laptop CPU)
Source is 30 FPS -> 33 ms budget: fits only on a quiet machine, with no headroom
First lever: export to OpenVINO or ONNX for this CPU, then vid_stride=2 if still short