Ultralytics YOLO27: Únete a la lista de espera.
Get Started
Entrena tu primer modelo YOLO·Publicar·Lección 9/10
Lecciónprincipiante

Ejecutar inferencia en vídeo

Ejecuta YOLO26 con archivos de vídeo y cámaras en directo con memoria acotada, sigue objetos para contar cada uno una sola vez y comprueba que el modelo mantiene la frecuencia de fotogramas.

La mayoría de los sistemas de visión desplegados analizan vídeo: cámaras sobre cintas transportadoras, puertas y carreteras. El vídeo plantea dos problemas que no existen con las imágenes individuales. Memoria: no se puede mantener una grabación larga en la RAM. Identidad: un detector ve a la misma persona en 60 fotogramas y la cuenta como 60 personas.

En esta lección transmitirás vídeo fotograma a fotograma con el modo Predict, añadirás el seguimiento de objetos para contar a cada persona una sola vez, escribirás tu propio bucle de cámara y medirás si el modelo mantiene el ritmo.

Resultado

Puedes transmitir vídeo o imágenes de una cámara con YOLO26 usando memoria acotada, contar objetos únicos mediante el seguimiento y decidir, según los milisegundos medidos por fotograma, si el modelo mantiene el ritmo de la fuente.

Vía rápida
Si ya tienes experiencia, aquí tienes un resumen.
  1. model(video, stream=True) produce un Results por fotograma con memoria acotada.

  2. model.track(video, stream=True, persist=True, tracker='bytetrack.yaml') añade boxes.id.

  3. Cuenta los objetos únicos con un conjunto de ID, nunca con el ID más alto.

  4. Presupuesto = 1000 ÷ FPS de la fuente; compáralo con result.speed['inference'].

Práctico

Ejemplo práctico: hacer predicciones en un archivo de vídeo#

Los vídeos usan el mismo modo Predict que las imágenes. Este clip de 62 fotogramas muestra a personas cruzando un atrio:

yolo predict model=yolo26n.pt source=https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4
video 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/predict
  • frame 1/62: Ultralytics decodifica el vídeo y procesa cada fotograma como si fuera una imagen.
  • 22 persons: detecciones en ese fotograma. Los mismos peatones se vuelven a contar en cada fotograma.
  • 27.3ms ... 54.8ms: el tiempo por fotograma varía según lo que esté haciendo el equipo.

El vídeo anotado es runs/detect/predict/solutions_ci_demo.mp4. Tu propio modelo funciona igual: sustituye yolo26n.pt por runs/detect/pills_v1/weights/best.pt.

Transmitir fuentes largas y en directo#

Para ejecutar código con las detecciones, recorre el flujo en un bucle. Cada iteración devuelve el Results de un fotograma y, después, lo descarta:

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

El mismo bucle acepta el índice de una cámara web (source=0) o una URL de cámara como rtsp://camera.local/stream, y se ejecuta hasta que termina el flujo o lo detienes. Añade vid_stride=2 para procesar un fotograma de cada dos. Para crear una interfaz web en torno a este bucle, la guía de inferencia en directo con Streamlit lo integra en una aplicación.

Ejemplo práctico: contar a cada persona una sola vez#

«22 personas por fotograma» no es la cifra que interesa; lo que interesa es «cuántas personas han pasado por aquí». El seguimiento de múltiples objetos enlaza las cajas entre fotogramas, y el modo Track asigna a cada objeto un ID en 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 tracked

is_track es False en los fotogramas anteriores a la confirmación de cualquier seguimiento, cuando boxes.id es None. Usa los ID para contar, calcular trayectorias o aplicar una lógica del tipo «este objeto lleva aquí 3 segundos».

Seguimiento de Ultralytics YOLO en una autopista: cada coche, autobús y camión lleva una etiqueta de ID persistente y un rastro de movimiento

RastreadorVelocidadRobustez
bytetrack.yamlMás rápido y sencilloPierde los ID con más frecuencia cuando los objetos desaparecen brevemente
botsort.yamlMás lentoMantiene mejor los ID cuando se mueve la cámara (compensación del movimiento; ReID por apariencia es opcional mediante with_reid)

Si omites tracker, Ultralytics usa tracktrack.yaml, el valor predeterminado actual; el modo Track también incluye ocsort.yaml, deepocsort.yaml y fasttrack.yaml. La elección y el ajuste de los rastreadores, así como la creación de contadores de objetos, mapas de calor y estimaciones de velocidad con ellos, se explican en Seguimiento de objetos con ByteTrack, BoT-SORT y TrackTrack.

Ejemplo práctico: tu propio bucle de cámara#

Las aplicaciones reales suelen leer los fotogramas directamente —para cambiar su tamaño, recortarlos, añadirles marcas de tiempo o compartir una cámara con otro código— y pasar cada uno al modelo. En ese caso, persist=True es lo que mantiene activo el rastreador entre llamadas:

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

Los mismos 32 personas que con track.py. Fíjate en que el ID más alto es 67, no 32: el rastreador también asigna ID a seguimientos provisionales que nunca se confirman, por lo que hay saltos en la numeración.

Mantener el ritmo de la fuente#

Una cámara de 30 FPS entrega un fotograma cada 33 ms, y la frecuencia efectiva es la más lenta de entre la decodificación, la inferencia y la escritura. En la CPU de nuestro portátil, yolo26n tardó entre 26 y 46 ms por fotograma de 384×640 en distintas ejecuciones, según lo que estuviera haciendo el equipo: se alcanza o se supera el presupuesto, sin margen. Si tu equipo no puede mantener el ritmo, prueba estas medidas por orden:

MedidaEfecto
Modelo más pequeño (n en lugar de s)A menudo, entre 2 y 3 veces más rápido
Reduce imgsz (480 en lugar de 640)Menos píxeles y menos cálculo; los objetos pequeños son los primeros en verse afectados
vid_stride=2Reduce el trabajo a la mitad; adecuado para escenas con poco movimiento
Una GPU o una exportación optimizadaLas mayores mejoras: un motor TensorRT en NVIDIA o INT8; consulta la siguiente lección

El uso simultáneo de varias cámaras y los hilos necesarios se explican en Inferencia con varios flujos.

Evita estos errores#

Olvidarse de stream=True

Síntoma: el uso de memoria aumenta hasta que el proceso se cierra durante una grabación larga, o una llamada a una cámara en directo no devuelve nunca el control. Causa: sin ese parámetro, la llamada de Python recopila un objeto Results por cada fotograma antes de devolver los resultados. Solución: pasa stream=True y recorre el generador; no hace nada hasta que lo iteras.

Olvidarse de persist=True en tu propio bucle

Síntoma: en cv2_loop.py sin persist=True, el recuento bajó a 27 y el ID más alto también era 27: los ID se reiniciaban en cada fotograma, así que el recuento «único» era solo el del fotograma con más objetos. Solución: pasa persist=True cada vez que llames a track una vez por fotograma.

Contar usando el ID más alto

Síntoma: un recuento de 67 para 32 personas. Causa: hay saltos en los ID porque algunas trayectorias no se confirmaron. Solución: cuenta el tamaño de un conjunto de ID, como en track.py.

Indica explícitamente el rastreador

El rastreador predeterminado puede cambiar entre versiones. Pasa tracker="bytetrack.yaml" (o el que prefieras) para que los recuentos sigan siendo comparables entre versiones.

Pruébalo

Ejecuta track_any.py (en la solución) con el clip de demostración y, después, con un vídeo corto tuyo. Entrega un informe de tres líneas: el recuento de objetos únicos, la media de milisegundos de inferencia por fotograma y si ese tiempo cabe dentro del intervalo entre fotogramas de la fuente, indicando qué medida aplicarías primero si no cabe. Guarda una salida anotada con yolo track ... save=True e indica si los ID se mantienen estables durante las oclusiones; si cambian constantemente, prueba tracker=botsort.yaml.

Cuándo se considera terminado
Has terminado la lección cuando se cumplen todas estas condiciones.
  • Has guardado un vídeo anotado con yolo predict o yolo track.

  • Tu script de transmisión muestra un recuento de objetos únicos a partir de un conjunto de valores boxes.id.

  • Has comparado los milisegundos medidos por fotograma con el intervalo entre fotogramas de la fuente y has indicado la primera medida que aplicarías para acelerar el proceso.

Mostrar solución
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")

Ejecútalo con 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
Qué viene después

Tu modelo funciona con imágenes y vídeos en Python. Último paso: expórtalo a un formato que pueda cargar un entorno de ejecución de producción.