Exécuter l'inférence sur une vidéo
Exécute YOLO26 sur des fichiers vidéo et des caméras en direct avec une mémoire bornée, suis les objets pour ne compter chacun qu'une fois et vérifie que le modèle suit la cadence d'images.
La plupart des systèmes de vision déployés analysent des vidéos : caméras au-dessus de convoyeurs, de portes et de routes. La vidéo pose deux problèmes que les images isolées ne posent pas. Mémoire : un long enregistrement ne peut pas être conservé en RAM. Identité : un détecteur voit la même personne dans 60 images et en signale 60.
Dans cette leçon, tu vas diffuser la vidéo image par image avec le mode Predict, ajouter le suivi d'objets pour compter chaque personne une seule fois, écrire ta propre boucle de caméra et mesurer si ton modèle suit la cadence.
Pratique
Exemple pratique : effectuer une prédiction sur un fichier vidéo#
Les vidéos utilisent le même mode Predict que les images. Cet extrait de 62 images montre des personnes traversant un atrium :
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 décode la vidéo et traite chaque image comme une image fixe.22 persons: détections dans cette image. Les mêmes passants sont comptés à nouveau dans chaque image.27.3ms...54.8ms: le temps par image varie selon les autres tâches effectuées par la machine.
La vidéo annotée est runs/detect/predict/solutions_ci_demo.mp4. Ton propre modèle fonctionne de la même manière : remplace yolo26n.pt par runs/detect/pills_v1/weights/best.pt.
Diffuser des flux longs et en direct#
Pour exécuter du code sur les détections, parcours un flux en boucle. Chaque itération génère le Results d'une image, puis le supprime :
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 frameLa même boucle accepte l'index d'une webcam (source=0) ou une URL de caméra telle que rtsp://camera.local/stream, et s'exécute jusqu'à la fin du flux ou jusqu'à ce que tu l'arrêtes. Ajoute vid_stride=2 pour traiter une image sur deux. Pour créer une interface Web autour de cette boucle, le guide Inférence en direct avec Streamlit l'intègre dans une application.
Exemple pratique : compter chaque personne une seule fois#
« 22 personnes par image » n'est pas le nombre que l'on cherche ; on veut savoir « combien de personnes sont passées ». Le suivi multi-objets relie les boîtes d'une image à l'autre, et le mode Track attribue à chaque objet un ID dans 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 correspond à False dans les images précédant la confirmation d'une piste, lorsque boxes.id vaut None. Utilise les ID pour compter, tracer des trajectoires ou appliquer une logique du type « cet objet est ici depuis 3 secondes ».

| Suiveur | Vitesse | Robustesse |
|---|---|---|
bytetrack.yaml | Plus rapide, plus simple | Perd plus souvent les ID lorsque des objets disparaissent brièvement |
botsort.yaml | Plus lent | Conserve mieux les ID lorsque la caméra bouge (compensation du mouvement ; la réidentification par apparence est facultative et s'active via with_reid) |
Si tu omets tracker, Ultralytics utilise tracktrack.yaml, la valeur par défaut actuelle ; le mode Track propose aussi ocsort.yaml, deepocsort.yaml et fasttrack.yaml. Le choix et le réglage des suiveurs, ainsi que la création de comptages d'objets, de cartes thermiques et d'estimations de vitesse à partir de ces suiveurs, sont abordés dans Suivre des objets avec ByteTrack, BoT-SORT et TrackTrack.
Exemple pratique : créer ta propre boucle de caméra#
Les applications réelles lisent souvent elles-mêmes les images — pour les redimensionner, les recadrer, les horodater ou partager une caméra avec d'autres codes — puis les transmettent au modèle. Dans ce cas, persist=True permet au suiveur de rester actif entre les appels :
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 67Même 32 personnes que dans track.py. Note que l'ID le plus élevé est 67, et non 32 : le suiveur attribue aussi des ID à des pistes provisoires qui ne sont jamais confirmées, d'où les discontinuités dans les ID.
Suivre la cadence de la source#
Une caméra à 30 FPS fournit une image toutes les 33 ms, et la cadence effective correspond à la plus lente des étapes de décodage, d'inférence et d'écriture. Sur le CPU de notre ordinateur portable, yolo26n a pris entre 26 et 46 ms par image de 384×640 au fil des exécutions, selon les autres tâches effectuées par la machine : le temps atteint ou dépasse le budget, sans aucune marge. Si ton système ne suit pas la cadence, essaie ces leviers dans l'ordre :
| Levier | Effet |
|---|---|
Modèle plus petit (n au lieu de s) | Souvent 2 à 3 fois plus rapide |
Réduire imgsz (480 au lieu de 640) | Moins de pixels, moins de calculs ; les petits objets sont les premiers à en pâtir |
vid_stride=2 | Divise la charge par deux ; convient aux scènes où les mouvements sont lents |
| Un GPU ou un export optimisé | Les gains les plus importants : un moteur TensorRT sur NVIDIA, ou INT8 ; consulte la leçon suivante |
L'utilisation simultanée de plusieurs caméras et le multithreading associé sont abordés dans Inférence mult flux.
Éviter ces erreurs#
Symptôme : la mémoire augmente jusqu'à ce que le processus s'arrête sur un long enregistrement, ou un appel à une caméra en direct ne renvoie jamais de résultat. Cause : sans ce paramètre, l'appel Python collecte un objet Results pour chaque image avant de renvoyer le résultat. Solution : passe stream=True et itère sur le générateur — il ne fait rien tant que tu ne l'itères pas.
Symptôme : dans cv2_loop.py sans persist=True, le décompte est tombé à 27 et l'ID le plus élevé était également 27 : les ID recommençaient à chaque image, si bien que le nombre « unique » correspondait simplement à l'image la plus chargée. Solution : passe persist=True chaque fois que tu appelles track une fois par image.
Symptôme : un décompte de 67 pour 32 personnes. Cause : les ID comportent des lacunes dues aux pistes non confirmées. Solution : compte le nombre d'éléments dans un ensemble d'ID, comme dans track.py.
Le traqueur par défaut peut changer d'une version à l'autre. Passe tracker="bytetrack.yaml" (ou celui de ton choix) pour que les décomptes restent comparables entre les versions.
Afficher la solution
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")Exécute-le avec 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