/ Модель

Характеристики

Лицензия
Apache 2.0
Библиотека
sportcv
Опубликована
16 сен 2026

sportcv-ballnet

Классификация и разметка

Компактная ONNX-модель для поиска мяча для пиклбола на кадрах трансляции 1080p.

0скачиваний за 30 дней0лайковвеса обновлены7 окт 2026

Бенчмарки

Как модель справилась с задачами пользователей ailist и что о ней публикуют открытые лидерборды

Публичные оценки

Из открытых лидербордов. Сравнивайте результаты одного теста при одинаковых условиях — отсутствие оценки не значит, что модель хуже.

В подключённых источниках результатов для этой модели пока нет.

Что умеет модель

Описание составлено по карточке модели и метаданным Hugging Face

sportcv-ballnet — небольшая тепловая сеть BallNet шириной 32, разработанная для проекта sportcv. Она находит мяч для пиклбола на кадрах трансляции с разрешением 1080p: принимает целый кадр, дополненный до размера, кратного 32, и выдаёт тепловую карту, из которой получают координаты пика с субпиксельным смещением и оценкой уверенности. Модель поставляется в формате ONNX; автор сообщает о времени обработки 9,88 мс на RTX 3060 в FP16 и 2,50 мс на RTX A6000 с TensorRT FP16.

На отложенном отрезке одного матча медианная ошибка позиции составила 1,73 пикселя, а мяч обнаруживался в пределах 8 пикселей в 94,5% случаев. Модель обучена на 396 размеченных кадрах из одного матча и намеренно подогнана под конкретные освещение, камеру и площадку. Она предназначена для анализа трансляции пиклбола, а не для произвольных спортивных видео; поскольку сеть всегда выдаёт пик, при использовании нужен порог уверенности. Лицензия — Apache-2.0.

Сценарии применения

  • поиск мяча для пиклбола на кадрах трансляции
  • получение координат мяча для построения траектории
  • анализ видео матча пиклбола покадрово

Ограничения

Обучена на 396 кадрах одного матча и специально подогнана под одну камеру, освещение и площадку; качество на других видео не измерялось. Сеть всегда выдаёт пик, поэтому для отсева ложных срабатываний необходим порог уверенности.

Карточка модели

README от автора на Hugging Face, как он его опубликовал

Открыть на Hugging Face

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

ArchitectureBallNet, width 32, output stride 4, single heatmap + sub-pixel offset
Inputfull frame padded to a multiple of 32 (1920×1088 for 1080p)
Outputone heatmap; decoded to a peak position in pixels plus a confidence
Trained80 epochs (checkpoint at epoch 65), ~30 min on one A40, $0.35

Measured

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

MetricValue
Median peak error1.73 px
Within 8 px94.5%
Confidence, ball present0.90 median
Confidence, ball absent0.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).

Basketball: ballnet-hoop-v2

The same architecture trained for a basketball broadcast filmed by one camera that pans and zooms from a fixed point (PTZ), on full 1080p frames with no court crop. It is the ball model of sportcv's basketball pilot.

ArchitectureBallNet, width 32, output stride 4, single heatmap + sub-pixel offset
Training927 three-frame stacks at 25 fps from two stretches of one match, 60 epochs on one L4, checkpoint at epoch 25 (best on the held-out span)
Held outframes 22034-22283 of the match, 241 stacks, never trained on

Measured on those 241 held-out frames, against the earlier model on the same frames:

v1v2
Ball within 8 px74.5%82.3%
Confidence on frames with no ball (median, lower is better)0.240.18
Median peak error1.74 px2.67 px

The median error does not favour v1 the way it looks: 110 of the 221 labelled positions in that span were kept from a pre-annotation made with v1's own path, so v1 scores close to zero there by construction. The share within 8 px is the comparison that survives that bias.

ballnet-hoop-v2.peaks.onnx: frames in, ball candidates out

The pre- and post-processing are inside the graph, so a runtime needs no sportcv code around it.

Input framesuint8 (3, 1080, 1920, 3): three consecutive frames as OpenCV decodes them, BGR, oldest first
Insidezero padding at the bottom to 1088, the frames' channels stacked oldest first, /255, BallNet, sigmoid, 3x3 peak suppression, peaks of at least 0.03, the 5 strongest with their sub-pixel offsets
Output peaksfloat32 (5, 3): x, y, score in source pixels for the middle frame, strongest first; a row with score 0 is no peak

Against sportcv's own Python path (stacking, padding and topk_peaks) on 12 real stacks of the match, the exported peaks moved 0.0001 px at most and the scores 3.6e-7. The shape is fixed to the camera it was trained for.

Limitations

  • One match, one camera. It is overfitted to this broadcast on purpose, like the pickleball head, and it is unmeasured on anything else.
  • It returns candidates, not the ball: sportcv picks the ball's path among the peaks of consecutive frames (a Viterbi search in the camera's stabilised view), and a single frame's strongest peak is wrong often enough to matter.

Training data

FILIPENSES - VENTA DE BAÑOS (J8 LIGA 2018/2019), by Filipenses Baloncesto Senior Masculino on YouTube, licensed CC BY 3.0. https://www.youtube.com/watch?v=D4XdbDp0vz0. Attribution to the uploader is required in any output derived from it.

Files

Filesha256What
ballnet.pt2081bc6c…57a8cathe checkpoint sp-detect loads
ballnet.onnx962d7a4a…0f9d3083FP32 ONNX, the portable artifact
ballnet.fp16.onnx4641d2cc…13c1eFP16 ONNX for strongly-typed TensorRT
ballnet-hoop-v2.pt08d1fb0a…3c302dcethe basketball checkpoint
ballnet-hoop-v2.peaks.onnxfdbc10b8…ed3e19c1the basketball model end to end: frames in, peaks out

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 is required in any output derived from it: @pickleball4you for the pickleball head, Filipenses Baloncesto Senior Masculino for the basketball one — 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

Как запустить

На своей GPU в ailist. Цена — по текущим предложениям провайдеров

GPU в ailist

Универсальный рантайм · sportcv

Нельзя запустить

В репозитории нет config.json: не понять архитектуру модели.

Ревизия весов
aa6d9fc

0 моделей