Pluggable Python and C++ multi-object tracking modules for axis-aligned and oriented bounding box detections from any model.
Docs • Installation • Modes • API Reference • Trackers • Contributing
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,export-edgetam,install, and nativebuildworkflows. - 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 production-ready native C++ tracker implementations with the same metrics as the Python path, opted into via
--tracker-backend cppand embeddable in standalone C++ projects via 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
boxmot --help
The default package uses the standard PyPI PyTorch build. Source checkouts and
CI can explicitly select the lockfile-backed cpu or cu130 profile. For
those profiles and mode-specific extras such as yolo, service, evolve,
research, onnx, openvino, and tflite, see the
installation guide.
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
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 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
from boxmot import EagerMot
tracker = EagerMot()
camera = np.array([ # synthetic camera projection
[100, 0, 100, 0],
[0, 100, 50, 0],
[0, 0, 1, 0],
])
camera_to_world = np.eye(4)
camera_to_world[0, 3] = 1.0 # synthetic pose: camera at world x = 1 meter
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,
image_size=(100, 200), # height, width
camera_to_world=camera_to_world,
)
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
camera_to_world throughout the sequence to track in camera coordinates.
Contributing
Start with CONTRIBUTING.md and the contributor docs.
Contributors
Support and Citation
- Bugs and feature requests: GitHub Issues
- Questions and discussion: GitHub Discussions or Discord
- Limited free consulting is available for nonprofit nature conservation projects using BoxMOT. Contact
box-mot@outlook.comto discuss your project. - Citation metadata: CITATION.cff
- Commercial support:
box-mot@outlook.com
Metadata
Release files for boxmot 26.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| boxmot-26.0.0.tar.gz | 1.5 MB | Without provenance | Details for boxmot-26.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| boxmot-26.0.0-py3-none-any.whl | Python 3 | none | any | Details for boxmot-26.0.0-py3-none-any.whl |
Total release size: 3.4 MB
Release files / boxmot-26.0.0.tar.gz
| Download URL | boxmot-26.0.0.tar.gz |
|---|---|
| Size | 1.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f2bb0715c0491dbb68721e65f970fb7aa0589d36b91598015441bf76bc76c568
|
|
BLAKE2b-256 checksum How to use checksums |
8a0d196237d814ac46ded09649b15a70339a88aac0193285555c4c31615fbf59
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.4 {"installer":{"name":"uv","version":"0.12.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / boxmot-26.0.0-py3-none-any.whl
| Download URL | boxmot-26.0.0-py3-none-any.whl |
|---|---|
| Size | 1.9 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7802ab588f5ca350dc444ed807337cccf6da2c977c4f89b50aad3e1b27d3d6a0
|
|
BLAKE2b-256 checksum How to use checksums |
e5c7ddf681bb89dc861a74c66b8a053165688e66e2dd25b43ec0dffd370ab787
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.4 {"installer":{"name":"uv","version":"0.12.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for boxmot 26.0.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.