BoxMOT provides independent detector, segmentor, appearance-encoder, and tracker
components built around validated Torch structures. Pipelines compose those
components; the CLI owns sources, outputs, materialized datasets, evaluation,
tuning, research, and ReID workflows.
Why BoxMOT
- One interface for
track, materialize, materialize --time-variant, eval,
tune, research, train-reid, eval-reid, compare-reid, export,
install, and native build workflows.
- Swappable components with explicit capabilities and requirements.
- Immutable, keyed Parquet builds with reusable detections, masks, and
embeddings.
- Support for both AABB and OBB tracking paths.
- Optional native C++ tracker implementations selected with
--tracker-backend cpp, with shared detection/output contracts and documented backend differences. They are also embeddable in standalone C++ projects through CMake (see Native C++ Integration and platform dependency installation).
- A structured Python API for embedding components and pipelines in applications.
Installation
BoxMOT supports Python 3.10 through 3.13.
pip install boxmot "ultralytics>=8.4.58"
boxmot --help
This installs BoxMOT and the Ultralytics detector backend used below. For
tracking existing detections through the Python API, pip install boxmot is
enough. See Installation for optional
workflows and PyTorch and source setup for
CPU/CUDA profiles and YOLOX.
Benchmark Results
| Tracker key |
Status |
MOT17 ablation |
SportsMOT val |
MMOT OBB test |
OBB |
| HOTA |
MOTA |
IDF1 |
HOTA |
MOTA |
IDF1 |
HOTA |
MOTA |
IDF1 |
| occluboost |
✅ |
71.10 (71.10) |
78.50 (78.50) |
85.28 (85.28) |
83.17 |
97.48 |
89.36 |
49.84 (49.84) |
39.41 (39.41) |
58.60 (58.60) |
✅ |
| botsort |
✅ |
69.68 (69.74) |
78.23 (78.27) |
82.33 (82.55) |
76.93 |
98.11 |
78.30 |
52.31 (52.40) |
45.43 (45.53) |
61.42 (61.42) |
✅ |
| boosttrack |
✅ |
69.25 (—) |
75.91 (—) |
83.20 (—) |
76.32 |
97.08 |
77.82 |
48.39 (—) |
41.36 (—) |
56.36 (—) |
✅ |
| strongsort |
✅ |
68.05 (—) |
76.19 (—) |
80.76 (—) |
79.80 |
97.31 |
80.27 |
49.76 (—) |
43.70 (—) |
57.32 (—) |
✅ |
| deepocsort |
✅ |
67.95 (—) |
75.83 (—) |
80.54 (—) |
79.51 |
97.94 |
79.59 |
50.84 (—) |
44.21 (—) |
59.33 (—) |
✅ |
| bytetrack |
✅ |
67.68 (67.68) |
78.04 (78.04) |
79.16 (79.16) |
67.93 |
97.25 |
76.90 |
33.97 (33.97) |
33.72 (33.72) |
39.74 (39.74) |
✅ |
| hybridsort |
✅ |
67.31 (—) |
74.09 (—) |
78.87 (—) |
81.14 |
98.07 |
81.88 |
54.64 (—) |
47.50 (—) |
64.67 (—) |
✅ |
| ocsort |
✅ |
66.44 (66.44) |
74.55 (74.55) |
77.90 (77.90) |
76.34 |
96.60 |
75.64 |
28.64 (28.64) |
26.17 (26.17) |
30.06 (30.06) |
✅ |
| sfsort |
✅ |
62.65 (62.65) |
76.87 (76.87) |
69.18 (69.18) |
75.73 |
98.39 |
72.99 |
47.83 (47.83) |
45.42 (45.42) |
52.09 (52.09) |
✅ |
Scores are Python first and C++ in parentheses.
MMOT reported metrics are 'class average'. See Experiment Workflows for details.
Related guides:
Minimal Usage
The mode guides provide
toggleable CLI and Python examples for tracking, materialization,
evaluation, tuning, research, ReID training, and export. Python workflow
functions accept settings directly as keyword arguments.
Select a command, detector, ReID model, tracker, and other settings interactively:
boxmot ui
The terminal UI previews the command before you run it and
enables an interactive dashboard for workflows that report live progress.
CLI:
boxmot track --detector yolo26n --reid lmbn_n_duke --tracker occluboost \
--source 0 --save --show
Evaluate a tracker:
boxmot eval \
--dataset mot17 \
--split ablation \
--detector yolox-x-mot17 \
--reid lmbn-n-duke \
--tracker botsort
Python trackers except SFSORT, plus native ByteTrack, BotSort, OcSort, and
OccluBoost, support opt-in capture timing with --variable-dt or
KalmanConfig(variable_dt=True). The Python API requires a timestamp on every
update. SFSORT uses fixed steps on both backends. See
elapsed-time tracking.
Python with axis-aligned boxes (AABB):
import numpy as np
from boxmot import OccluBoost
tracker = OccluBoost()
dets = np.array([[100, 200, 300, 400, 0.9, 0]])
frame = np.zeros((480, 640, 3), dtype=np.uint8) # BGR image
tracks = tracker.update(dets, frame)
print(tracks[:, 4].astype(int)) # track IDs
Python with oriented boxes (OBB):
import numpy as np
from boxmot import OccluBoost
tracker = OccluBoost(is_obb=True)
# cx, cy, width, height, angle in radians, confidence, class_id
dets = np.array([[200, 300, 200, 100, np.pi / 6, 0.9, 0]])
frame = np.zeros((480, 640, 3), dtype=np.uint8) # BGR image
tracks = tracker.update(dets, frame)
print(tracks[:, 5].astype(int)) # track IDs
2D/3D sensor fusion with ego-motion compensation using EagerMot:
import numpy as np
import torch
from boxmot import EagerMot
from boxmot.structures import CameraModel
tracker = EagerMot()
projection = torch.tensor([ # synthetic camera projection
[100, 0, 100, 0],
[0, 100, 50, 0],
[0, 0, 1, 0],
], dtype=torch.float32)
camera_to_world = torch.eye(4, dtype=torch.float32)
camera_to_world[0, 3] = 1.0 # synthetic pose: camera at world x = 1 meter
camera = CameraModel(
projection=projection,
image_size=(100, 200), # height, width
camera_to_world=camera_to_world,
)
dets = np.array([[78, 39, 122, 62, 0.95, 0]])
# 3D in camera coordinates: x, y, z, yaw, length, width, height, confidence, class_id
dets_3d = np.array([[0, 1, 10, 0, 4, 2, 2, 0.9, 0]])
tracks_2d, tracks_3d = tracker.update(
dets,
detections_3d=dets_3d,
camera=camera,
)
print(tracks_2d[:, 4].astype(int)) # image track IDs
print(tracks_3d[:, 7].astype(int)) # 3D track IDs
Replace the synthetic pose with the current frame’s absolute 4×4 camera-to-world
transform on every update. KITTI evaluation loads these from poses.npy when
the dataset declares a poses modality. If poses are unavailable, omit
CameraModel.camera_to_world throughout the sequence to track in camera
coordinates. A NumPy camera projection can also be passed with a frame that
provides its image dimensions; use CameraModel when no frame is supplied.
License
BoxMOT is licensed under the GNU Affero General Public License v3 (AGPL-3.0).
Each detector and segmentor integrated with BoxMOT retains its own upstream
license. See the respective project’s license for its terms. Other third-party
components also retain their respective licenses and notices.
Contributing
Start with CONTRIBUTING.md and the contributor docs.
Contributors
Support and Citation
评论