An OpenCV and Python tennis-broadcast analysis pipeline that detects two on-court players, a tennis ball, court landmarks, and renders an annotated match video with a top-down mini-court and stable analytics dashboard.
- YOLOv8 player detection and court-aware filtering to retain only the two players.
- Custom YOLO ball detection with size, court-region, static-detection, and temporal filters.
- Fourteen court keypoints with a homography-based mapping to metric court coordinates.
- Annotated broadcast overlay: frame counter, player IDs, ball ID, and court landmark IDs.
- Semi-transparent mini-court with player/ball markers and a fading ball trajectory trail.
- Readable analytics dashboard with cadence-controlled player and shot estimates.
analytics/ Analytics and dashboard state management
court/ Mini-court rendering and homography mapping
court_line_detector/ ResNet50 court-keypoint inference
trackers/ YOLO player and ball tracking
ui/ OpenCV overlay renderer
utils/ Video read/write helpers
training/ Court-keypoint training script
main.py End-to-end pipeline entry point
Use Python 3.10 or later. Create and activate a virtual environment, then install the dependencies:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txtFor a CUDA-enabled PyTorch build, install the matching torch and torchvision packages from PyTorch before installing the remaining dependencies.
Large videos, model weights, generated output, and tracking caches are intentionally excluded from Git. Before running, provide these local files:
input_videos/input_video.mp4
models/yolo5_best.pt
models/keypoints_model.pth
yolov8x.pt
The pipeline automatically creates output_videos/ and tracker_stubs/ when needed. Do not commit videos or model weights unless you use Git LFS and have permission to distribute them.
From the project root:
python main.pyThe annotated video is written to output_videos/output_video.avi.
The output includes green frame numbering; player, ball, and keypoint labels; a top-right mini-court with a fading 1.5-second ball trail; and a cadence-controlled statistics dashboard.
Shot metrics update only on detected hit events. Player speed uses a 0.75-second rolling buffer and visibly refreshes every 0.5 seconds; its average refreshes every second to avoid unreadable per-frame flicker.
- The included court checkpoint currently does not produce valid landmarks for the bundled broadcast. The pipeline therefore uses the calibrated Vienna fallback by default.
- That fallback is camera-specific. Set
ALLOW_VIENNA_FALLBACK = Falseinmain.pyfor a new camera view and supply a validated court model or manual calibration. - Ball trajectory, hit detection, and speeds are estimates; they depend on detections and homography quality.
Train to a candidate path first, inspect the generated validation image, and only then promote it to the active model:
python training\train_court_keypoints.py --epochs 20 --batch-size 16 --output models\keypoints_candidate.pthReview output_videos/court_keypoint_validation.jpg before replacing models/keypoints_model.pth.