Real-time sports analytics toolkit built on the Roboflow ecosystem
Project description
SportVision
Real-time sports analytics toolkit built on the Roboflow ecosystem. Detects players and ball with any COCO-compatible model (YOLOv8, RF-DETR, etc.), tracks with ByteTrack, classifies teams by jersey color, and computes possession, speed, distance, and heatmaps.
Features
- Detection — Works with any COCO-compatible detector (YOLOv8, RF-DETR, etc.)
- Tracking — ByteTrack via supervision with fallback sequential IDs
- Team Classification — KMeans on HSV jersey histograms
- Homography — Pixel→field coordinate mapping via
cv2.findHomography - Analytics — Possession, speed, distance, and heatmap generation
- Annotation — Team-colored bounding boxes, stats overlay, player trails
Quick Start
pip install sportvision
from sportvision.pipeline import SportVisionPipeline
pipeline = SportVisionPipeline()
result = pipeline.process_frame(frame)
Roboflow Workflows Plugin
SportVision ships as a Roboflow Workflows plugin. Install with inference and activate:
pip install "sportvision[workflows]"
export WORKFLOWS_PLUGINS="sportvision.workflows"
This registers 4 blocks you can use in any Roboflow Workflow:
| Block | Type Identifier | Description |
|---|---|---|
| Team Classifier | sportvision/team_classifier@v1 |
Clusters players into teams by jersey color. refit_every=N to periodically refit KMeans. |
| Possession Tracker | sportvision/possession_tracker@v1 |
Tracks ball possession per team over time. Warns when team_id is missing. |
| Distance Calculator | sportvision/distance_calculator@v1 |
Cumulative distance per tracked player. Supports homography_matrix for field-unit distances. |
| Sports Detection Filter | sportvision/sports_detection_filter@v1 |
Filters COCO detections to sports classes |
Example: Using blocks directly in Python
import cv2
import numpy as np
import supervision as sv
from sportvision.workflows.team_classifier.v1 import TeamClassifierBlockV1
from sportvision.workflows.possession_tracker.v1 import PossessionTrackerBlockV1
from sportvision.workflows.distance_calculator.v1 import DistanceCalculatorBlockV1
from sportvision.workflows.sports_detection_filter.v1 import SportsDetectionFilterBlockV1
# --- Filter COCO detections to sports classes ---
det_filter = SportsDetectionFilterBlockV1()
# Assume `raw_detections` comes from a COCO model (person=0, sports_ball=32)
result = det_filter.run(detections=raw_detections)
detections = result["detections"] # now player=0, ball=1
# --- Classify players into teams ---
team_block = TeamClassifierBlockV1()
# `image` must have a .numpy_image attribute (or use WorkflowImageData)
# refit_every=10 refits KMeans every 10 frames (0 = fit once, default)
result = team_block.run(image=image, detections=detections, n_teams=2, refit_every=10)
detections = result["detections"] # detections.data["team_id"] is now set
# --- Track possession ---
possession_block = PossessionTrackerBlockV1()
result = possession_block.run(
detections=detections,
ball_class_id=1,
ball_proximity_threshold=100.0,
)
print(result["possession_stats"]) # {0: 0.6, 1: 0.4}
print(result["possessing_team"]) # 0
print(result["warning"]) # "" or warning if team_id missing
# --- Compute distances ---
distance_block = DistanceCalculatorBlockV1()
# Optional: pass a 3x3 homography matrix for field-unit distances (e.g. meters)
result = distance_block.run(detections=detections, homography_matrix=[[0.01,0,0],[0,0.01,0],[0,0,1]])
print(result["detections"].data["distance"]) # cumulative distance per tracker
Example: Workflow JSON definition
{
"steps": [
{
"type": "sportvision/sports_detection_filter@v1",
"name": "filter",
"detections": "$steps.model.predictions"
},
{
"type": "sportvision/team_classifier@v1",
"name": "teams",
"image": "$inputs.image",
"detections": "$steps.filter.detections",
"n_teams": 2,
"refit_every": 10
},
{
"type": "sportvision/possession_tracker@v1",
"name": "possession",
"detections": "$steps.teams.detections",
"ball_proximity_threshold": 100.0
},
{
"type": "sportvision/distance_calculator@v1",
"name": "distance",
"detections": "$steps.teams.detections",
"homography_matrix": [[0.01,0,0],[0,0.01,0],[0,0,1]]
}
]
}
Try it on Colab
Architecture
src/sportvision/
├── detection.py # SportsDetector — wraps COCO detectors, maps to sports classes
├── tracking.py # SportsTracker — ByteTrack via supervision
├── teams.py # TeamClassifier — KMeans on HSV jersey histograms
├── homography.py # FieldHomography — pixel→field coords
├── analytics/
│ ├── possession.py # PossessionTracker — nearest-player-to-ball per frame
│ ├── speed.py # SpeedEstimator — displacement/time → km/h
│ ├── distance.py # DistanceCalculator — cumulative path length
│ └── heatmap.py # HeatmapGenerator — 2D histogram + gaussian blur
├── annotators.py # TeamColorAnnotator, StatsOverlayAnnotator, TrailAnnotator
├── pipeline.py # SportVisionPipeline — orchestrates all modules
└── workflows/ # Roboflow Workflows plugin
├── _compat.py # Inference compatibility shim
├── kinds.py # Custom kind definitions
├── team_classifier/ # Team classification block
├── possession_tracker/ # Possession tracking block
├── distance_calculator/ # Distance calculation block
└── sports_detection_filter/ # COCO→sports filter block
Sports Class IDs
| ID | Class |
|---|---|
| 0 | Player |
| 1 | Ball |
| 2 | Referee |
| 3 | Goalkeeper |
Dependencies
| Package | Purpose | Required |
|---|---|---|
| numpy | Arrays | Yes |
| opencv-python | Image processing, annotation | Yes |
| supervision | Detection/tracking data structures | Yes |
| scikit-learn | KMeans for team classification | Yes |
| pydantic | Workflow block manifests | Yes |
| inference | Roboflow Workflows engine | Optional ([workflows]) |
| ultralytics | YOLOv8 detection | Optional |
| rfdetr | RF-DETR detection | Optional ([inference]) |
Development
git clone https://github.com/MohibShaikh/sportvision.git
cd sportvision
pip install -e ".[all]"
# Tests
pytest tests/ -v
# Lint
ruff check src/ tests/ && ruff format --check src/ tests/
License
Apache-2.0
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sportvision-0.2.3.tar.gz.
File metadata
- Download URL: sportvision-0.2.3.tar.gz
- Upload date:
- Size: 602.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
016e0704d7bf1a2ea8eb17d71870ac38ef657d16d6c2904845050bf575768d5f
|
|
| MD5 |
10b6027a9c41748ba3d2147d46b33e44
|
|
| BLAKE2b-256 |
f8baba50ea40b38f9fb9f235b902373060b07863a466c629830fb957a1df1593
|
File details
Details for the file sportvision-0.2.3-py3-none-any.whl.
File metadata
- Download URL: sportvision-0.2.3-py3-none-any.whl
- Upload date:
- Size: 25.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b9547530b687ecba425192ee27509201117967f9b9affc977772e9f35d8dd23
|
|
| MD5 |
05863341a2c4b4ae050d1bed171f076a
|
|
| BLAKE2b-256 |
b9703c797aec4e61a8d8bac0572d63d798ca0099f78b9e587b2ade2ada5496db
|