BoxMOT logo

Pluggable Python and C++ multi-object tracking modules for axis-aligned and oriented bounding box detections from any model.

[![CI](https://github.com/mikel-brostrom/boxmot/actions/workflows/ci.yml/badge.svg)](https://github.com/mikel-brostrom/boxmot/actions/workflows/ci.yml) [![Coverage](https://codecov.io/gh/mikel-brostrom/boxmot/branch/master/graph/badge.svg)](https://app.codecov.io/gh/mikel-brostrom/boxmot/tree/master) [![PyPI version](https://badge.fury.io/py/boxmot.svg)](https://badge.fury.io/py/boxmot) [![downloads](https://static.pepy.tech/badge/boxmot)](https://pepy.tech/project/boxmot) [![license](https://img.shields.io/badge/license-AGPL%203.0-blue)](https://github.com/mikel-brostrom/boxmot/blob/master/LICENSE) [![python-version](https://img.shields.io/pypi/pyversions/boxmot)](https://badge.fury.io/py/boxmot) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.8132989.svg)](https://doi.org/10.5281/zenodo.8132989) [![colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/18nIqkBr68TkK8dHdarxTco6svHUJGggY?usp=sharing) [![discord](https://img.shields.io/discord/1377565354326495283?logo=discord&label=discord&labelColor=fff&color=5865f2)](https://discord.gg/tUmFEcYU4q) [Ask DeepWiki](https://deepwiki.com/mikel-brostrom/boxmot) mikel-brostrom%2Fboxmot | Trendshift --- [Docs](docs/index.md) • [Installation](docs/getting-started/installation.md) • [Modes](docs/modes/index.md) • [API Reference](docs/python/index.md) • [Trackers](docs/trackers/index.md) • [Contributing](CONTRIBUTING.md) BoxMOT demo
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 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 production-ready native C++ tracker implementations with the same metrics as the Python path, opted into via `--tracker-backend cpp` and embeddable in standalone C++ projects via CMake (see [Native C++ Integration](docs/native/index.md) and [platform dependency installation](docs/native/index.md#install-dependencies)). - A structured Python API for embedding components and pipelines in applications. ## Installation BoxMOT supports Python `3.10` through `3.13`. ```bash 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](docs/getting-started/installation.md). ## 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: - [Evaluation and Postprocessing](docs/guides/evaluation.md) - [Experiment Workflows](docs/guides/experiments.md) - [Native C++ Integration](docs/native/index.md) ## Minimal Usage CLI: ```bash boxmot track --detector yolo26n --reid lmbn_n_duke --tracker occluboost \ --source 0 --save --show ``` Evaluate a tracker: ```bash boxmot eval \ --dataset mot17 \ --split ablation \ --detector yolox-x-mot17 \ --reid lmbn-n-duke \ --tracker botsort ``` Python with axis-aligned boxes (AABB): ```python 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): ```python 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](docs/trackers/eagermot.md): ```python 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](CONTRIBUTING.md) and the [contributor docs](docs/contributing/index.md). ## Contributors BoxMOT contributors ## Support and Citation - Bugs and feature requests: [GitHub Issues](https://github.com/mikel-brostrom/boxmot/issues) - Questions and discussion: [GitHub Discussions](https://github.com/mikel-brostrom/boxmot/discussions) or [Discord](https://discord.gg/tUmFEcYU4q) - Limited free consulting is available for nonprofit nature conservation projects using BoxMOT. Contact `box-mot@outlook.com` to discuss your project. - Citation metadata: [CITATION.cff](https://github.com/mikel-brostrom/boxmot/blob/master/CITATION.cff) - Commercial support: `box-mot@outlook.com`