motrackers: four multi-object trackers behind one update() call
Multi-object trackers in Python
At a glance
- What is it?
- The adipandas/multi-object-tracker package wraps CentroidTracker, IOUTracker, CentroidKF_Tracker and SORT behind a shared Python interface, with OpenCV DNN detectors for YOLOv3, Caffe SSD and TensorFlow SSD MobileNet. It is a readable reference implementation, not a production tracking service.
- Who is it for?
- Adopt motrackers if you need a small, MIT-licensed Python tracker to attach to an existing detector, or if you want to read and modify tracking code rather than treat it as a black box. Do not adopt it if you need appearance-based re-identification, per-class track identity across long occlusions, or a maintained benchmark against published MOT metrics; the README itself notes that the SORT and IoU Tracker implementations vary from the papers.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 61 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What motrackers actually replaces in a detection pipeline
An object detector answers a question per frame: where are the objects now. It has no memory. Run YOLOv3 or MobileNet SSD on a video and you get a fresh set of boxes each frame with no relationship to the boxes from the frame before, so you cannot count how many distinct cars passed a camera or follow one animal through a herd. motrackers supplies that missing layer. It takes the detector output, assigns stable integer ids, and returns tracks. The intended user is someone who already has OpenCV DNN detection working and wants tracking without pulling in a full framework. The README's own framing is modest: an easy to use implementation of various multi-object tracking algorithms. That word, implementation, is the honest description. This is a library of algorithms you can read, not a service.
The four trackers and how they differ in mechanism
The package ships CentroidTracker, IOUTracker, CentroidKF_Tracker and SORT. The names indicate the association cost each one uses. CentroidTracker matches detections to existing tracks by distance between bounding box centroids. IOUTracker matches by intersection over union between the new box and the predicted or previous box, which is the approach from the IoU Tracker paper. CentroidKF_Tracker keeps the centroid association but adds a Kalman filter, so track state is predicted forward rather than assumed static. SORT combines a Kalman filter with IoU-based association and is the closest of the four to a published baseline. The practical consequence is that the choice is not cosmetic. Centroid matching degrades when objects pass close together and centroids swap. IoU matching degrades when objects move fast relative to their size, because consecutive boxes may not overlap at all. A Kalman filter helps in that second case, which is why the two filter-based options exist. The README does not publish accuracy figures for any of them, so the selection has to be made by running the examples on your own footage.
The data contract: numpy arrays in, ten-element tuples out
Every tracker exposes the same call. You construct one, then in a loop call tracker.update(detection_bboxes, detection_confidences, detection_class_ids). The inputs are numpy arrays: bounding boxes of shape (n, 4), confidences of shape (n,), and class ids of shape (n,). The README specifies the box layout as (bb_left, bb_top, bb_width, bb_height), which is width and height rather than right and bottom. That detail matters because many detectors and annotation formats emit corner coordinates, and a silent mismatch produces tracks that look plausible and are wrong. The return value is a list of tuples, each with exactly ten elements: frame, id, bb_left, bb_top, bb_width, bb_height, confidence, x, y, z. The example code asserts len(track) == 10, which is the kind of check worth keeping. The x, y, z fields are present in the tuple regardless of tracker, so a 2D tracker leaves the depth slot unused. Because all four trackers share this signature, swapping CentroidTracker for SORT is a one-line change in the construction call, which is the strongest argument for the package's design.
Detectors, weights and the GPU build you may have to do yourself
Three OpenCV DNN detectors are provided: detector.TF_SSDMobileNetV2, detector.Caffe_SSDMobileNet and detector.YOLOv3. They are not bundled with weights. The README states plainly that you have to download the pretrained weights, and that shell scripts for doing so live under examples/pretrained_models in per-model folders, with DOWNLOAD_WEIGHTS.md giving the details. Plan for that step; a fresh pip install motrackers gives you the tracker code and the detector wrappers, not a working model. The GPU note is the sharper constraint. To run these OpenCV dnn detectors on a GPU, the README says you may have to compile a CUDA-enabled version of OpenCV from source, and links to OpenCV and PyImageSearch build guides. That is a real afternoon of work with its own failure modes, and it sits outside the pip install. If your detector is already running somewhere else, in PyTorch or TensorFlow directly, you can skip the bundled detectors entirely and feed their output into tracker.update, since the interface is just numpy arrays.
Installation, tests and the Python version floor
Installation is a single command, pip install motrackers, with OpenCV 3.4.3 or later required. The README also documents the source route: clone the repository, change into multi-object-tracker, then pip install [-e] . where the -e flag gives an editable install. The package requires Python 3.10 or later, which is a hard floor and rules it out on older interpreters still common in embedded and legacy vision stacks. For testing, the documented sequence is pip install -e ".[test]" followed by pytest. Note that the test extra is only declared in the source install path, so the editable install is the one to use if you intend to run or extend the suite. There are no published releases in the material supplied, so version pinning has to be done against the repository state or the PyPI package as it stands.
Where the implementation diverges from the papers
The README carries a short but important note: there are some variations in implementations as compared to what appeared in papers of SORT and IoU Tracker. It does not enumerate them. Anyone treating this package as a reference implementation of SORT for a paper or a benchmark should read the source of the tracker they intend to use before citing results from it, because the association logic, the Kalman filter parameters, or the track lifecycle thresholds may not match the published version. The same note is also the maintenance signal: the author invites pull requests and issues for algorithm bugs, which suggests a single-maintainer project where correctness fixes arrive through community patches rather than a scheduled release process. That is workable for a library of this size and a poor fit for anything with a compliance or reproducibility requirement attached.
When a different tool is the better answer
The clearest alternative is a full tracking framework with appearance modelling, of which the most commonly cited in this space is the tracking-by-detection family that includes Deep SORT and its successors. The difference is not scale, it is the association signal. Every tracker in motrackers associates on geometry alone: centroid distance, IoU, or a Kalman-predicted position. None of them extract an appearance embedding from the image. So when two objects cross, or one is occluded for several frames and re-emerges elsewhere, a geometry-only tracker has nothing to match on except position, and it will either drop the track or hand the id to the wrong object. An appearance-based tracker computes a descriptor per detection and matches on that as well, which costs an extra network pass per box. If your scenes have dense crowds, frequent occlusion, or objects that leave and re-enter, motrackers is the wrong tool and no amount of parameter tuning fixes it. If your objects are well separated and move smoothly, the geometric approach is cheaper and easier to debug, and the extra network pass buys nothing.
Licence, maintenance and what you are taking on
The licence is MIT, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. That is permissive and imposes no copyleft obligation on your own code, though the usual caveat applies: the bundled detector wrappers and the pretrained weights you download separately may carry their own terms, and YOLOv3 weights in particular have historically been distributed under terms distinct from the code. Check the weight licences independently; nothing in the repository can settle that for you. On maintenance cost, the material shows a single author, an archived status of no, and a last push in July 2026, but no releases. The upgrade surface is small: four tracker classes behind one interface, plus three detector wrappers. The realistic ongoing cost is not patching the library, it is re-validating your tracker choice whenever you change detector, resolution or frame rate, because the association thresholds that worked at one frame rate will not necessarily work at another. Budget for that re-tuning rather than assuming the default constructor arguments carry over.
Editorial conclusion
Adopt motrackers if you need a small, MIT-licensed Python tracker to attach to an existing detector, or if you want to read and modify tracking code rather than treat it as a black box. Do not adopt it if you need appearance-based re-identification, per-class track identity across long occlusions, or a maintained benchmark against published MOT metrics; the README itself notes that the SORT and IoU Tracker implementations vary from the papers. Before committing, verify three things: that your Python is 3.10 or later, that the pretrained weights download scripts under examples/pretrained_models still resolve for the detector you intend to use, and that the ten-element tuple returned by tracker.update matches the coordinate convention your downstream code expects, since the bounding box is width and height, not right and bottom.
Community notes