Tennis ball bounce detector

Decides whether the ball touched the court, from the shape of its trajectory. HistGradientBoostingClassifier over 16 scale-free trajectory features.

Measured results

Trained on the TrackNet tennis dataset: 95 clips, 10 professional matches, 920 labelled bounces.

split precision recall F1 PR-AUC
held-out clips 0.888 0.944 0.915 0.956
leave-one-match-out 0.951

Leave-one-match-out is the honest number: clips from one match share a court, a camera and a pair of players, so a clip-level split lets the model see the same camera during training. 0.951 across ten unseen matches says it transfers.

Why a classifier and not a threshold

The geometric rule this replaces used a single prominence threshold on the ball's height signal. Swept against ground truth, no value of that threshold found every point - so the parameter had no correct setting and the model was wrong, not the tuning.

The bug worth knowing about

The candidate proposal stage originally offered only frames where the ball's projected court y was a local maximum. Against 136 real labelled bounces that is true 2% of the time: a bounce is a corner in the trajectory, not a peak, because the height signal also carries down-court travel and that term usually dominates. Proposal recall was 34.6%. Proposing on the upward kink in image y instead - normalised by the segment's median speed, so it is resolution independent - took it to 99.3%. No classifier can recover an event that was never proposed.

Input

16 features per candidate, in this order:

image_kink, height_prominence_left, height_prominence_right, height_curvature, reversal_sharpness, speed_before, speed_after, speed_ratio, direction_change_deg, vertical_velocity_before, vertical_velocity_after, vertical_velocity_flip, court_y_at_candidate, distance_inside_court_m, interpolated_share, mean_confidence

Court-space features are in metres and need a court homography.

import joblib
model = joblib.load("bounce_model.joblib")
probability = model.predict_proba(features)[:, 1]

Requires scikit-learn 1.9+ (pickled there; older versions load with a warning and may give different answers).

Training data

TrackNet tennis dataset - 81 broadcast clips, 10 matches, 30 fps, per-frame ball coordinates with a status column where 2 marks ground contact.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support