Downloads · 30 days
63
53% of all-time downloads
grdesignbuild/volleyball-jersey-number-reader
volleyball-jersey-number-reader is a image classification model from grdesignbuild. Use it when you need a label for an image. It is set up for transformers. The card lists the license as apache-2.0.
Reads the jersey number on a person crop from volleyball footage, or says the number is not readable. Companion to grdesignbuild/volleyball-person-ball-detector: the detector finds the people, this model reads their n…
Downloads · 30 days
63
53% of all-time downloads
All-time downloads
118
Public
Parameters
11.2M
67.2 MB on disk
Likes
0
Public
Click a slice to open those files.
.safetensors44.8 MB · 67%
From the Hugging Face model README
Reads the jersey number on a person crop from volleyball footage, or says the number is not readable. Companion to grdesignbuild/volleyball-person-ball-detector: the detector finds the people, this model reads their numbers, and together they attach moments and stats to a player.
The model has 23 logits in three groups, so it can read numbers it never saw in training:
| logits | meaning |
|---|---|
| 0–9, 10 | tens digit 0–9, or blank (single-digit number) |
| 11–20 | ones digit 0–9 |
| 21, 22 | unreadable / readable |
Decode: if readable wins, the number is tens + ones ("7" when tens is blank, "07" when tens is 0).
read_number.py in this repo does this and also cuts the right crop.
Feed the chest of a person box: from 10 % to 60 % of the box height (skipping the head), widened 10 % per side, resized to 224×224. That is exactly what the training crops were, and the processor config here passes a square 224 image through untouched.
from transformers import AutoImageProcessor, AutoModelForImageClassification
from PIL import Image
import torch
repo = "grdesignbuild/volleyball-jersey-number-reader"
processor = AutoImageProcessor.from_pretrained(repo)
model = AutoModelForImageClassification.from_pretrained(repo).eval()
crop = Image.open("torso.jpg").convert("RGB") # see read_number.torso() for the crop rule
with torch.no_grad():
logits = model(**processor(images=crop, return_tensors="pt")).logits[0]
tens, ones, readable = logits[:11].softmax(-1), logits[11:21].softmax(-1), logits[21:].softmax(-1)
if readable[1] > 0.5:
t, o = int(tens.argmax()), int(ones.argmax())
print(str(o) if t == 10 else f"{t}{o}")
else:
print("not readable")
Against the teacher's reads on held-out recordings:
| metric | value |
|---|---|
| number accuracy on readable crops | 0.671 |
| precision of predicted numbers | 0.588 |
| readable precision / recall | 0.866 / 0.988 |
| precision of numbers at confidence ≥ 0.85 | 0.79 (recall 0.49) |
The teacher's own held-out labels are about one in ten wrong on inspection, so true accuracy is somewhat higher than these figures. In practice, read every frame of a tracked player and keep numbers with confidence ≥ 0.85; two or three agreeing reads identify the player reliably.
Apache-2.0. Built with 🤗 Transformers.