Compteur automatique de jongles avec YOLO
Application web qui utilise YOLOv8 pour compter automatiquement les jongles réalisés avec un ballon de football sur des vidéos.
Introduction
Je suis passionné de football, et même si je suis incapable de dépasser 10 jongles consécutifs dans la vraie vie, j'ai toujours voulu créer un logiciel qui a une utilité concrète dans le sport. Pour cela, j'ai décidé d'utiliser ce que j'avais appris pendant la deuxième année de mon cycle d'ingénieur à l'EPITA, notamment en vision par ordinateur, pour concevoir un compteur automatique de jongles à partir d'une simple vidéo.
L'objectif de Juggle Count est de concevoir un pipeline de vision par ordinateur et de deep learning de bout en bout capable de :
- Détecter et traquer la trajectoire d'un ballon de football.
- Estimer les points clés articulaires du corps du joueur (pose estimation).
- Distinguer un véritable jongle d'un rebond au sol ou d'un mouvement parasite (ce qui n'est pas si évident).
- Visualiser en temps réel le comptage et la trajectoire du ballon sur la vidéo avec un HUD dynamique.
Architecture & Stack Technique
J'ai choisi de développer ce projet en Python, notamment parce que cela m'a permis d'intégrer facilement YOLOv8, un modèle pré-entraîné très performant de détection d'objets et d'estimation de pose.
Pour les moldus qui passeraient par là, YOLOv8 est un modèle léger et rapide, édité par Ultralytics. Son gros point fort est d'être pré-entraîné sur le jeu de données COCO (Common Objects in Context), qui contient 80 classes d'objets, dont la classe "ballon de sport" (n°32). Il est donc directement capable de détecter un ballon de football sans nécessiter d'entraînement spécifique préalable.
Dans mon cas, cela me facilite énormément la tâche, car je n'ai pas besoin de collecter et d'annoter des milliers d'images de ballons. Je peux ainsi me concentrer sur l'implémentation du pipeline algorithmique de suivi vidéo et sur l'expérience utilisateur !
J'utilise également ce modèle pour la pose estimation, ce qui me permet d'extraire les coordonnées des articulations clés du joueur (tête, épaules, hanches, genoux et chevilles) afin de vérifier si le ballon est bien en contact avec son corps.
En termes de framework web, je suis parti sur FastAPI, couplé à une interface web légère accessible depuis n'importe quel navigateur, développée en HTML/CSS/JS vanilla.
Sans trop rentrer dans les détails d'architecture, FastAPI me permet d'exécuter chaque traitement vidéo en tâche de fond asynchrone pour ne pas bloquer le serveur. L'interface web peut ainsi afficher une barre de progression et le nombre de jongles comptés en direct.
Comme c'est une notion abordée dans mes cours de Deep Learning, j'ai aussi mis en place une détection automatique du matériel afin d'exploiter l'accélération GPU via CUDA si une carte NVIDIA est disponible, avec un fallback transparent sur CPU.
Détection et suivi spatial du ballon
Comme dit plus tôt, la détection du ballon repose sur le modèle yolov8s.pt filtré sur la classe COCO n°32 (sports ball).
Sur une vidéo de football, le ballon est souvent soumis à un fort flou de mouvement (motion blur), à des occlusions partielles lorsqu'il passe devant les jambes, ou à des confusions avec d'autres éléments circulaires en arrière-plan.
Pour assurer la continuité temporelle de la trajectoire, j'ai trouvé un petit algorithme qui permet d'évaluer les candidats détectés en pénalisant la distance par rapport au dernier centre connu du ballon.
Cette méthode évite les 'sauts' vers de faux positifs éloignés.
Estimation de pose & validation anatomique
Compter un jongle ne consiste pas simplement à détecter le moment où le ballon remonte, car si la balle rebondit au sol ou si quelqu'un la lance à la main depuis l'extérieur du champ, le compteur ne doit évidemment pas s'incrémenter.
Le modèle yolov8n-pose.pt extrait simultanément les coordonnées des principales articulations du joueur (nez, épaules, hanches, genoux et chevilles) :
TARGET_JOINTS = [0, 5, 6, 11, 12, 13, 14, 15, 16]
Le ballon a deux phases de mouvement : une phase descendante (FALLING) et une phase ascendante (RISING), dont l'inversion est détectée par la variation verticale de sa position (). Pour valider un jongle, il faut que le ballon soit en contact avec le corps du joueur au moment de l'impact.
Si ce contact a lieu à moins de 130 pixels d'une articulation du corps, le jongle est validé, le compteur s'incrémente et l'état bascule sur RISING.
Cet algorithme est assez naïf, mais fonctionne plutôt bien sur des vidéos de bonne qualité, et quand le joueur est de profil.
Interface Web
Je me suis amusé à concevoir un overlay graphique pour visualiser l'analyse en temps réel directement sur le flux vidéo.
Chaque image traitée est enrichie visuellement :
- Traînée cinématique : Un ruban dégradé orange relie les 20 dernières coordonnées du ballon pour matérialiser sa dynamique.
- Boîte englobante réactive : Encadre le ballon en jaune lors du vol, et s'illumine en vert vif au moment précis de l'impact validé.
- Squelette articulaire : Marqueurs circulaires sur les articulations suivies du joueur reliées par des segments semi-transparents.
- Overlay HUD translucide : Affiche en haut à gauche le nombre total de jongles validés et l'état courant du système (
FALLING/RISING).
Problèmes rencontrés & solutions
Je déteste les iPhones
Un gros problème auquel je me suis confronté concerne la manière dont les vidéos sont capturées et stockées sur smartphone, en particulier sous iOS.
Lorsqu'une vidéo est filmée en mode portrait, le flux vidéo brut est souvent encodé en paysage avec un tag d'affichage EXIF/FFmpeg de 90°. Par défaut, OpenCV lit les frames sans appliquer cette rotation, ce qui produit une vidéo couchée et inverse complètement les axes et pour le calcul de trajectoire. (Et évidemment, ayant moi-même un iPhone, j'étais bien obligé de régler ce problème !)
J'ai donc dû implémenter une correction de rotation pour réorienter correctement chaque frame avant son passage dans les modèles YOLO.
Tolérance aux pertes de détection du ballon
Quand le ballon passe rapidement derrière une jambe ou subit un flou extrême, la détection peut échouer pendant 2 ou 3 frames consécutives. Pour éviter de casser la séquence, l'algorithme tolère jusqu'à 10 frames sans détection avant de réinitialiser le tampon de trajectoire, ce qui améliore robustesse de l'algorithme.
Conclusion
Ce projet m'a permis d'expérimenter avec YOLO en dehors d'un cadre purement académique, ce que j'ai trouvé intéressant surtout dans le cadre d'un projet lié au sport. J'ai aussi pu approfondir l'utilisation de FastAPI, que j'avais déjà découvert lors de mon projet de segmentation pulmonaire, et que je trouve particulièrement agréable et efficace pour construire des API de traitement.
Le projet reste perfectible, avec plusieurs pistes d'évolution envisageables :
- La distinction automatique du membre utilisé (pied gauche, pied droit, tête, genou).
- Le calcul de statistiques complémentaires (hauteur moyenne des jongles, cadence, régularité).
- L'analyse en streaming direct via WebRTC depuis la caméra d'un smartphone.