Ultralytics YOLO27 : Inscris-toi sur la liste d’attente.
Get Started
Entraîne ton premier modèle YOLO·Déployer·Leçon 9/10
Leçondébutant

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.

Résultat

Tu peux diffuser une vidéo ou le flux d'une caméra avec YOLO26 en utilisant une mémoire bornée, compter les objets uniques grâce au suivi et déterminer, à partir du temps mesuré en ms par image, si le modèle suit la cadence de la source.

Parcours accéléré
Si tu connais déjà les bases, voici la version courte.
  1. model(video, stream=True) génère un Results par image avec une mémoire bornée.

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

  3. Compte les objets uniques à l'aide d'un ensemble d'ID, jamais en prenant l'ID le plus élevé.

  4. Budget = 1000 ÷ FPS de la source ; compare-le à result.speed['inference'].

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.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 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 frame

La 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 tracked

is_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 ».

Suivi Ultralytics YOLO sur une autoroute : chaque voiture, autobus et camion porte une étiquette d'ID persistante et une trajectoire

SuiveurVitesseRobustesse
bytetrack.yamlPlus rapide, plus simplePerd plus souvent les ID lorsque des objets disparaissent brièvement
botsort.yamlPlus lentConserve 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 67

Mê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 :

LevierEffet
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=2Divise 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#

Oublier stream=True

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.

Oublier persist=True dans ta propre boucle

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.

Compter à partir de l'ID le plus élevé

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.

Indiquer explicitement le traqueur

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.

Essayer

Exécute track_any.py (dans la solution) sur l'extrait de démonstration, puis sur une courte vidéo de ton choix. Remets un rapport de trois lignes : le nombre d'objets uniques, le temps d'inférence moyen en ms par image et indique si ce temps respecte la cadence de ta source, en précisant le premier levier que tu actionnerais dans le cas contraire. Enregistre une sortie annotée avec yolo track ... save=True et indique si les ID restent stables lors des occultations ; s'ils fluctuent, essaie tracker=botsort.yaml.

Terminé lorsque
Tu as terminé la leçon lorsque tous les éléments suivants sont réunis.
  • Tu as enregistré une vidéo annotée à partir de yolo predict ou de yolo track.

  • Ton script de diffusion affiche un nombre d'objets uniques calculé à partir d'un ensemble de valeurs boxes.id.

  • Tu as comparé le temps mesuré en ms par image au temps entre les images de la source et indiqué le premier levier que tu actionnerais pour accélérer le traitement.

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
Et ensuite ?

Ton modèle fonctionne sur des images et des vidéos en Python. Dernière étape : exporte-le dans un format qu'un environnement d'exécution de production peut charger.