Skip to main content
Colab Roboflow identify-basketball-players-2 identify-basketball-players-1

Environment setup

Configure your API keys

To run this notebook, you need to provide your HuggingFace Token and Roboflow API key.
  • The ROBOFLOW_API_KEY is required to pull the fine-tuned RF-DETR player detector and the SmolVLM2 number recognizer from Roboflow Universe.
  • The HF_TOKEN is required to pull the pretrained SigLIP model from HuggingFace.
Follow these steps:
  • Open your HuggingFace Settings page. Click Access Tokens then New Token to generate a new token.
  • Go to your Roboflow Settings page. Click Copy. This will place your private key in the clipboard.
  • In Colab, go to the left pane and click on Secrets (🔑).
    • Store the HuggingFace Access Token under the name HF_TOKEN.
    • Store the Roboflow API Key under the name ROBOFLOW_API_KEY.

Check GPU availability

Let’s make sure we have access to a GPU. Run the nvidia-smi command to verify. If you run into issues, go to Runtime -> Change runtime type, select T4 GPU or L4 GPU, and then click Save.
NOTE: To make it easier for us to manage datasets, images and models we create a HOME constant.

Install SAM2 real-time

We will use segment-anything-2-real-time, an open-source fork of Meta’s Segment Anything Model 2 optimized for real-time inference. After installing the repository, we will also download the required checkpoint files.

Install dependencies

Set the ONNX Runtime execution provider to CUDA to ensure model inference runs on the GPU.

Source videos

As an example, we will use sample videos from Game 1 of the 2025 NBA Playoffs between the Boston Celtics and the New York Knicks. We prepared 10 sample videos from this game.

Team rosters

We are preparing player rosters for both teams. We load the official lists that link jersey numbers to player names. These mappings will let us replace detected numbers with real names, making the final analytics clear and readable.

Import dependencies

Object detection

The model used in this notebook detects the following classes: ball, ball-in-basket, number, player, player-in-possession, player-jump-shot, player-layup-dunk, player-shot-block, referee, and rim. These classes enable tracking of game events, player actions, and ball location for basketball analytics.

Load RF-DETR object detection model

Single frame object detection

output

Keep only “number” class

output
output

Full video object detection

We are running RF-DETR across all frames to produce a per-frame sequence of detections. These sequences seed tracking and provide number crops over time.

Player tracking

We are switching from frame-wise boxes to temporal tracks. SAM2 yields per-player masks and stable track IDs that persist through occlusions and re-entries.

Load SAM2 tracking model

We are loading a SAM2 checkpoint and config into the camera predictor. The large variant yields the highest quality masks; swap to smaller for speed if needed.

Full video player tacking

We are prompting SAM2 with RF-DETR boxes and tracking across the clip. The callback saves masks, IDs, and visualizations for downstream use.
output

Cluster players into teams

EWe are assigning each track to a team without labels. The pipeline uses SigLIP embeddings, UMAP to 3D, then K-means with k=2 for final team IDs.

Collecting training set

We are sampling frames at 1 FPS, detecting players, and extracting central crops. Central regions emphasize jersey color and texture while reducing background artifacts.
output

Train and test clustering model

We are computing SigLIP embeddings for crops, reducing with UMAP, and fitting K-means. A quick validation confirms separation by uniform appearance.
output output

Test clustering model on single video frame

We are applying the trained clustering to one frame’s player crops. The output assigns provisional team IDs to confirm the mapping before full-video use.
output output Since we do not control which IDs the clustering algorithm assigns to the teams, after training and testing we must select one of the dictionaries below.

Full video team clustering

We are assigning team IDs to tracks once, then reusing them across frames via track IDs. This keeps colors and labels consistent throughout the video.

Player numbers OCR

We are moving to jersey OCR to identify individuals within each team. Number reads pair with tracks and teams to resolve names later.

Load number recognition model

We are loading the fine-tuned SmolVLM2 OCR model by ID. It was trained on jersey crops and outputs digit strings suitable for downstream validation.

Single frame player number detection and recognition

We are detecting number boxes, padding, and cropping. We then run SmolVLM2 on each crop and preview predictions next to the regions.
output
output

Single frame player detection with number detection matching

We are matching numbers to players using Intersection over Smaller Area. IoS equals 1.0 implies the number lies fully inside the player mask, so we link them.
output output

Validating recognized numbers

We are confirming numbers across time using a consecutive-agreement threshold. The validator locks a number to a track only after repeated consistent reads.

Player recognition

We are overlaying names, numbers, team colors, and masks for each tracked player. The final render shows stable identities aligned with roster data across the full clip.

Court keypoints detection

Load keypoint detection model

Single frame keypoint detection

output

Detecting keypoints with high confidence

output

Map player positions to court coordinates

Single frame player position mapping

output output

Full video player position mapping

Clean player movement paths

We are detecting sudden jumps in position using robust speed analysis. We are removing short abnormal runs and nearby frames to eliminate teleport-like artifacts. We are filling missing segments with linear interpolation to ensure continuous motion. We are smoothing all paths with a Savitzky–Golay filter to achieve stable and natural movement.
output
output
output

Classify shorts as made or miss

Keep only “player-jump-shot” class

output

Mark jump-shot location on the court

output

Detect shot events

output
output
output
output

Looking for more tutorials or have questions? Check out our GitHub repo for more notebooks, or visit our discord.