Skip to main content

SportVision

Real-time sports analytics toolkit built on the Roboflow ecosystem. It detects players and the ball, tracks them with ByteTrack, clusters teams by jersey color, and computes possession, speed, distance, and heatmaps. Detection works with any COCO-compatible model, YOLOv8 and RF-DETR included.

Features

Detection. Works with any COCO-compatible detector, YOLOv8 and RF-DETR included.

Tracking. ByteTrack via supervision, with sequential IDs as the fallback when trackers is missing.

Team classification. KMeans on HSV jersey histograms.

Homography. Pixel to field coordinate mapping via cv2.findHomography.

Analytics. Possession, speed, distance, and heatmap generation.

Annotation. Team-colored bounding boxes, a stats overlay, and player trails.

Quick Start

pip install sportvision
from sportvision.pipeline import SportVisionPipeline

pipeline = SportVisionPipeline()
result = pipeline.process_frame(frame)

Detection needs a backend: pip install "sportvision[inference]" for RF-DETR, or install ultralytics for YOLO. Without one the pipeline returns empty detections and logs a warning once.

Two knobs make it run real-time on a GPU. detect_every=N runs detection every Nth frame and reuses the last result in between. infer_size caps the detector's input size (default 640) so the model sees fewer pixels; detection quality barely moves and boxes are mapped back to full frame coordinates.

pipeline = SportVisionPipeline(device="auto", detect_every=3, infer_size=640)

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

Open In 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 to field coords
├── analytics/
│   ├── possession.py # PossessionTracker, nearest player to the ball per frame
│   ├── speed.py      # SpeedEstimator, displacement over time to km/h
│   ├── distance.py   # DistanceCalculator, cumulative path length
│   └── heatmap.py    # HeatmapGenerator, 2D histogram plus 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

Metadata

Release files for sportvision 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sportvision 0.3.1
File Size Uploaded
sportvision-0.3.1.tar.gz 996.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sportvision 0.3.1
File Interpreter ABI Platform
sportvision-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 1.0 MB

Release files / sportvision-0.3.1.tar.gz

Download URL sportvision-0.3.1.tar.gz
Size 996.2 kB
Tags Source
SHA-256 checksum
How to use checksums
8515d75f6d183b3906151eefd41166f8a25baddd96030894dccd082547e08855
BLAKE2b-256 checksum
How to use checksums
efbcd348209b9ffb34e724c5d637b4b070b8149dcce8b3277809925815b9807c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.

Transparency log

Release files / sportvision-0.3.1-py3-none-any.whl

Download URL sportvision-0.3.1-py3-none-any.whl
Size 27.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
838362c3086ae7c987072978e02af6820da2dc4137463c7d7fe19055e95b1a61
BLAKE2b-256 checksum
How to use checksums
c555254dad6e59f27bfed6f86006d75c0aca5878b2dfef87907634cf98ffea67
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page