Football player detection and match analytics (YOLOv8)
Solo
2025–26
Analytics & ML
YOLOv8, PyTorch, OpenCV
A small model can pull usable detections straight from broadcast frames on an ordinary CPU. Choosing the inference resolution on validation data lifted ball detection from 0.29 to 0.43 without retraining, and the rebuilt model matches v1 overall while beating it on 3 of 4 classes.
01The problem
Tracking data normally needs expensive camera systems or manual tagging. Can a small model get usable detections straight from broadcast frames, on an ordinary CPU?
Cognitive Sciences and Analytics course, Semester 7, 2025 · v1 built on Roboflow; rebuilt end to end in Python in 2026 (v2) · Solo
02What I did
- Fine-tuned YOLOv8-nano on 372 labelled frames (Roboflow public dataset, CC BY 4.0).
- Chose the inference resolution on validation data, which lifted ball accuracy by half without retraining.
- Built team identification (jersey-colour clustering) and a possession estimate (nearest player to the ball).
03Results
v2: YOLOv8-nano (2026)v1: Roboflow (2025)
Test-set mAP@0.5 by class. Test frames share clips with training frames, so these are an upper bound for unseen matches.
Source: outputs/test_metrics.csv; v1 from notebook cell 16
Ball mAP@0.5 on the validation set, by inference size.
Source: notebook cell 12 (resolution sweep)
| Model | YOLOv8-nano, 3,133,436 parameters, fine-tuned from COCO weights |
|---|---|
| Labelled frames (train / validation / test) | 298 / 49 / 25 |
| Labelled objects (train / validation / test) | 7,133 / 1,174 / 598 |
| Source clips | 56 Bundesliga broadcast clips |
| Training | 43 epochs at 640 px, 1.75 h on CPU |
| Inference size | 960 px (chosen on validation set) |
| Speed | 244 ms per frame at 960 px on a 2-core CPU (about 4 fps), no GPU |
| Test mAP@0.5 | 0.826 at 960 px (0.787 at 640 px) |
Source: notebook cell 12; notebook cell 4; notebook cell 23; notebook cell 9; notebook cell 19; notebook cell 15
Speed is about 4 frames per second on a 2-core CPU.
04The ball is the bottleneck
When the model calls a ball it is right 95% of the time, but it finds only 38% of them, so possession can be estimated in only 47% of frames.