Multi-Object Tracking with Ultralytics YOLO#
Object tracking in the realm of video analytics is a critical task that not only identifies the location and class of objects within the frame but also maintains a unique ID for each detected object as the video progresses. The applications are limitlessโranging from surveillance and security to real-time sports analytics.
See the unreleased YOLO27 preview for planned tracking support.
Starting with ultralytics 8.4.63, OC-SORT, Deep OC-SORT, FastTracker, and TrackTrack are available alongside BoT-SORT and ByteTrack.
Why Choose Ultralytics YOLO for Object Tracking?#
The output from Ultralytics trackers is consistent with standard object detection but has the added value of object IDs. This makes it easy to track objects in video streams and perform subsequent analytics. Here's why you should consider using Ultralytics YOLO for your object tracking needs:
- Efficiency: Process video streams in real-time without compromising accuracy.
- Flexibility: Supports multiple tracking algorithms and configurations.
- Ease of Use: Simple Python API and CLI options for quick integration and deployment.
- Customizability: Easy to use with custom-trained YOLO models, allowing integration into domain-specific applications.
Watch: How to Run Multi-Object Tracking with Ultralytics YOLO26 | BoT-SORT & ByteTrack | VisionAI ๐
Real-world Applications#
| Transportation | Retail | Aquaculture |
|---|---|---|
| Vehicle Tracking | People Tracking | Fish Tracking |
Quick Start#
Run tracking on a video with the default TrackTrack tracker. Swap to another tracker by changing the tracker argument.
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
# Default tracker (TrackTrack)
results = model.track(source="https://youtu.be/LNwODJXcvt4", show=True)
# Switch to ByteTrack
results = model.track(source="https://youtu.be/LNwODJXcvt4", show=True, tracker="bytetrack.yaml")To run the tracker on video streams, use a trained Detect, Segment, Pose, or OBB model such as YOLO26n, YOLO26n-seg, YOLO26n-pose, or YOLO26n-obb. You can train custom models locally or with Ultralytics Platform cloud training.
from ultralytics import YOLO
# Load an official or custom model
model = YOLO("yolo26n.pt") # Load an official Detect model
model = YOLO("yolo26n-seg.pt") # Load an official Segment model
model = YOLO("yolo26n-pose.pt") # Load an official Pose model
model = YOLO("path/to/best.pt") # Load a custom-trained model
# Perform tracking with the model
results = model.track("https://youtu.be/LNwODJXcvt4", show=True) # Tracking with default tracker
results = model.track("https://youtu.be/LNwODJXcvt4", show=True, tracker="bytetrack.yaml") # with ByteTrackSupported Trackers#
Ultralytics YOLO ships with six built-in trackers. Enable one by passing its YAML config file to the tracker argument.
| Tracker | Config file | Motion model | Appearance / ReID | Camera motion compensation | Occlusion handling |
|---|---|---|---|---|---|
| BoT-SORT | botsort.yaml | Linear Kalman | Optional (with_reid) | Configurable (gmc_method) | Track buffer + ReID rebinding |
| ByteTrack | bytetrack.yaml | Linear Kalman | None | No | Two-stage low-conf rescue |
| OC-SORT | ocsort.yaml | Observation-centric Kalman | None | No | ORU, OCM, OCR re-update from last observation |
| Deep OC-SORT | deepocsort.yaml | Observation-centric Kalman | Optional (with_reid) | Configurable (gmc_method) | OC-SORT + optional adaptive appearance EMA |
| FastTracker | fasttrack.yaml | Linear Kalman + rollback | None | No | Kalman rollback + bbox enlargement on occlusion |
| TrackTrack | tracktrack.yaml | Linear Kalman (NSA) | Optional (with_reid) | Configurable (gmc_method) | Iterative multi-cue association + TAI |
Which Tracker Should I Use?#
Use this flow to pick a starting point; tracktrack.yaml is used when you pass no tracker:
- Need the fastest, simplest baseline? โ ByteTrack (no ReID, no camera-motion compensation, minimum overhead).
- Handheld, drone, or moving-camera footage? โ BoT-SORT (adds camera-motion compensation and optional ReID).
- Non-linear motion (sports, dancing, abrupt turns) and no ReID? โ OC-SORT (observation-centric corrections without appearance cost).
- Crowded moving-camera scenes where ID swaps are the main problem? โ Deep OC-SORT or TrackTrack (both support optional appearance matching; TrackTrack also adds multi-cue association and duplicate-ID suppression).
- Frequent partial overlap in real-time, no ReID budget? โ FastTracker (occlusion-aware ByteTrack variant with Kalman rollback).
Switching Trackers#
Pass the tracker config filename to tracker=. All other code stays the same.
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
results = model.track(source="path/to/video.mp4", tracker="bytetrack.yaml")
results = model.track(source="path/to/video.mp4", tracker="ocsort.yaml")
results = model.track(source="path/to/video.mp4", tracker="tracktrack.yaml")Configuration#
Tracking Arguments#
Tracking configuration shares properties with Predict mode, such as conf, iou, and show. For further configurations, refer to the Predict model page.
from ultralytics import YOLO
# Configure the tracking parameters and run the tracker
model = YOLO("yolo26n.pt")
results = model.track(source="https://youtu.be/LNwODJXcvt4", conf=0.1, iou=0.7, show=True)Custom Tracker Configuration#
Ultralytics also allows you to use a modified tracker configuration file. To do this, simply make a copy of a tracker config file (for example, custom_tracker.yaml) from ultralytics/cfg/trackers and modify any configurations (except the tracker_type) as per your needs.
from ultralytics import YOLO
# Load the model and run the tracker with a custom configuration file
model = YOLO("yolo26n.pt")
results = model.track(source="https://youtu.be/LNwODJXcvt4", tracker="custom_tracker.yaml")Shared Tracker Arguments#
The following parameters are common to most tracker YAML files; not every parameter appears in every config:
Detections at or above track_high_thresh enter the first association stage. Detections between track_low_thresh and track_high_thresh can recover existing tracks when the selected tracker enables low-confidence association, but they do not start new tracks. Detections at or below track_low_thresh are ignored.
| Parameter | Valid Values or Ranges | Description |
|---|---|---|
tracker_type | botsort, bytetrack, ocsort, deepocsort, fasttrack, tracktrack | Specifies the tracker type. |
track_high_thresh | 0.0-1.0 | Threshold for the first association. Affects how confidently a detection is matched to an existing track. |
track_low_thresh | 0.0-1.0 | Lower bound for low-confidence recovery detections. OC-SORT and Deep OC-SORT use these only when use_byte: True; TrackTrack includes them in its penalized association pool. |
new_track_thresh | 0.0-1.0 | Threshold to initialize a new track if the detection does not match any existing tracks. |
track_buffer | >=0 | Frames lost tracks are kept alive before removal. Higher value means more tolerance for occlusion. |
match_thresh | 0.0-1.0 | Threshold for matching tracks. Higher values make matching more lenient. |
fuse_score | True, False | Whether to fuse confidence scores with IoU distances before matching. |
gmc_method | sparseOptFlow, orb, sift, ecc, none | Global motion compensation method. Helps account for camera movement. |
proximity_thresh | 0.0-1.0 | Minimum IoU required for a valid ReID match. Ensures spatial closeness before using appearance cues. |
appearance_thresh | 0.0-1.0 | Minimum normalized appearance similarity required for ReID. |
with_reid | True, False | Enable appearance-based matching for better tracking across occlusions. Supported by BoT-SORT, Deep OC-SORT, and TrackTrack. |
model | auto or compatible ReID model path | ReID model. auto uses native YOLO backbone features when available; otherwise falls back to yolo26n-cls.pt. A custom encoder can be a .pt checkpoint or an exported model such as .torchscript, .onnx, .engine, or an OpenVINO model directory. |
Tracker-specific Arguments#
Each algorithm exposes additional knobs on top of the shared parameters. See the per-tracker sections below for descriptions and tuning advice, or refer directly to the config files:
Enabling Re-Identification (ReID)#
ReID is disabled by default to minimize overhead. Enable it by setting with_reid: True in a tracker config file.
ReID model options:
model: autoโ Uses native YOLO detector features, adding minimal overhead. Ideal when you need some ReID without a large performance hit. Falls back toyolo26n-cls.ptif the detector does not expose compatible features.- Custom ReID model โ Point
model:at a.ptcheckpoint or a compatible exported embedding model, such as.torchscript,.onnx,.engine, or an OpenVINO model directory. Exported models are loaded throughAutoBackendand must output an embedding tensor directly.
Ready-to-use ONNX encoders are published for every model size. Set model: to one of these names and the file is downloaded automatically the first time the tracker runs (the same way YOLO weights are fetched) โ no manual export or download step required:
# In your tracker config (e.g. tracktrack.yaml)
with_reid: True
model: yolo26n-reid.onnx # downloaded on first use; swap nโs/m/l/x for a larger encoder| Model | size (pixels) | params (M) | FLOPs (B) |
|---|---|---|---|
| YOLO26n-reid.onnx | 448 | 2.8 | 2.0 |
| YOLO26s-reid.onnx | 448 | 7.5 | 6.6 |
| YOLO26m-reid.onnx | 448 | 12.4 | 20.1 |
| YOLO26l-reid.onnx | 448 | 15.3 | 25.2 |
| YOLO26x-reid.onnx | 448 | 32.7 | 55.9 |
Only ONNX ReID encoders for the tracker appearance branch are currently available. ReID train, val, and predict modes, as well as dedicated ReID export recipes, are still under development.
For better performance with a separate classification model, export it to a faster backend like TensorRT:
from torch import nn
from ultralytics import YOLO
# Load the classification model
model = YOLO("yolo26n-cls.pt")
# Add average pooling layer
head = model.model.model[-1]
pool = nn.Sequential(nn.AdaptiveAvgPool2d((1, 1)), nn.Flatten(start_dim=1))
pool.f, pool.i = head.f, head.i
model.model.model[-1] = pool
# Export to TensorRT
model.export(format="engine", quantize=16, dynamic=True, batch=32)Once exported, point to the TensorRT model path in your tracker config.
Tracker Details#
The sections below describe each tracker's design, specific parameters, and tuning tips.
Watch: Which Object Tracker Performs Better? | Speed, FPS & ID Stability | Ultralytics YOLO26 ๐
BoT-SORT#
BoT-SORT (Aharon et al., 2022) extends ByteTrack with camera-motion compensation and optional ReID:
- Camera Motion Compensation (CMC): an affine warp estimated each frame (sparse optical flow by default; ORB / ECC also available) is applied to Kalman states before IoU matching.
- Optional ReID: appearance embeddings can be fused into the cost matrix. Disabled by default; enable with
with_reid: True.
Best for: general-purpose tracking, especially moving cameras. Add ReID only when look-alike crowds cause ID swaps.
BoT-SORT-specific arguments:
| Parameter | Valid Values or Ranges | Description |
|---|---|---|
gmc_method | sparseOptFlow, orb, sift, ecc, none | Camera-motion-compensation backend. sparseOptFlow is the default. none disables CMC. |
with_reid | True, False | Enable appearance-based matching. Off by default. |
model | auto or compatible ReID model path | auto uses native YOLO features when available; custom models can be .pt checkpoints or compatible exports. |
proximity_thresh | 0.0-1.0 | Minimum IoU before appearance features are considered. |
appearance_thresh | 0.0-1.0 | Minimum normalized appearance similarity required for a ReID match. Raise to make matching stricter. |
Tuning tips: