sportcv-ballnet

The ball head from sportcv: a small heatmap network that finds a pickleball in a 1080p broadcast-style frame.

It exists because the alternative did not fit. WASB was the plan, and at the resolution the ball needs it measured 58.6 ms per frame β€” 175% of a 33.37 ms budget. This head runs the same job at 9.88 ms (FP16, RTX 3060) and 2.50 ms on TensorRT FP16 (RTX A6000), which is what makes a full analysis pipeline finish faster than the clip plays on one 6 GB laptop GPU.

What it is

Architecture BallNet, width 32, output stride 4, single heatmap + sub-pixel offset
Input full frame padded to a multiple of 32 (1920Γ—1088 for 1080p)
Output one heatmap; decoded to a peak position in pixels plus a confidence
Trained 80 epochs (checkpoint at epoch 65), ~30 min on one A40, $0.35

Measured

On a held-out rally the model chose nothing on:

Metric Value
Median peak error 1.73 px
Within 8 px 94.5%
Confidence, ball present 0.90 median
Confidence, ball absent 0.07 median

Against all labels including the training window: 1.31 px median, 97% within 8 px. Over a 25.6-minute span the head was never trained on, it puts a trajectory on 76–89% of in-rally frames in every minute, median 80% β€” and the minute it was trained on is not the best one.

The raw detection rate across all frames is 47%, which says nothing about the model: the ball is mostly absent when nobody is playing.

Training data, and why it is this small

396 annotated frames from a single 60-second window β€” about 1.2% of that window β€” of one Creative Commons match. Labelling is the expensive input, so the project measured how little would do rather than assuming.

Source footage: *2026.07.25 WD Open β€” Sabrina Lam + Grace Thomas vs Lingzhe Xu

Limitations β€” read this before using it

  • It is overfitted to one match, on purpose. One ball, one set of lights, one camera, one court. It is not a general sports-ball detector and was never trying to be. Treat any other footage as unmeasured until you measure it.
  • Pickleball only. No other sport has been run through it.
  • The crowd wears the ball's colour, and the court crop was wrong for a while because the ball flies above the court. Both are documented failure modes in the project's DESIGN.md.
  • The head always produces a peak, so a confidence threshold is not optional. sp-detect uses 0.35; the distribution is cleanly bimodal (p25 0.047, p75 0.89).

Files

File sha256 What
ballnet.pt 2081bc6c…57a8ca the checkpoint sp-detect loads
ballnet.onnx 962d7a4a…0f9d3083 FP32 ONNX, the portable artifact
ballnet.fp16.onnx 4641d2cc…13c1e FP16 ONNX for strongly-typed TensorRT

Full hashes are pinned in src/sportcv/core/weights.py and checked on every load. A number is evidence only if the artifact behind it can be identified, and a filename identifies nothing.

No TensorRT engine is published here. An engine is tied to a TensorRT version and, without the Ampere-plus flag, to one GPU architecture, so it would be a 50 MB file that silently fails to load for most people. Build your own from ballnet.fp16.onnx; sportcv's exporter checks parity where it is used β€” in pixels of decoded peak movement against the 1.73 px held-out error β€” rather than as a tensor difference nobody can act on. Measured at 0.0008 px, which is 0.04% of the model's own error.

Use

uv run sp-detect data/<video>.mp4      # resolves and verifies these weights

Or directly:

import torch
from sportcv.core.ballnet import BallNet
from sportcv.core.weights import resolve

blob = torch.load(resolve("ballnet.pt"), map_location="cpu", weights_only=False)
model = BallNet(width=blob["width"]).eval()
model.load_state_dict(blob["state_dict"])

Licence

The weights and the code are Apache-2.0. The footage they were trained on is CC BY 3.0 and attribution to @pickleball4you is required in any output derived from it β€” YouTube grants 3.0, never 4.0, and the attribution must name the licence the licensor actually granted.

Citation

@software{condados_sportcv_2026,
  author = {Condados, Luis},
  title  = {sportcv: offline sports video analytics from one fixed camera},
  year   = {2026},
  url    = {https://github.com/CondadosAI/sportcv}
}

The architecture owes its framing to the WASB paper, which is the baseline it replaced: Tarashima et al., Widely Applicable Strong Baseline for Sports Ball Detection and Tracking, BMVC 2023. https://arxiv.org/abs/2311.05237

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

Paper for CondadosAI/sportcv-ballnet