How to Integrate Ultralytics YOLO Models with BoxMOT: A Complete Developer Guide
BoxMOT provides a unified detection and ReID pipeline that automatically detects and loads any Ultralytics YOLO model (e.g., yolov8n.pt, custom .pt files) through the DetectorReIDPipeline class, enabling seamless multi-object tracking without custom preprocessing code.
The mikel-brostrom/boxmot repository abstracts away the complexity of combining object detection with appearance-based ReID models. When you integrate Ultralytics YOLO models with BoxMOT, the framework handles model loading, inference orchestration, and tensor conversion automatically, letting you focus on tracking logic rather than boilerplate code.
How the Ultralytics YOLO Integration Works
BoxMOT implements a three-layer architecture to support Ultralytics models natively. The system detects Ultralytics weights automatically and routes inference through optimized wrappers.
Core Integration Components
The integration relies on three specific source files that form a detection backend abstraction:
-
Ultralyticsdetector (boxmot/detectors/ultralytics.py) – A thin wrapper that loads models via theYOLO()constructor and implements theload → preprocess → process → postprocessflow required by the genericDetectorbase class. -
DetectorReIDPipeline(boxmot/engine/inference.py) – Also exported asYOLOInference, this high-level engine creates the YOLO object, registers inference callbacks, and optionally wraps ReID models for synchronized timing measurements. -
Detectorbase class (boxmot/detectors/detector.py) – Provides the generic contract includingresolve_image, weight loading utilities, and the__call__workflow that the Ultralytics detector inherits.
The Inference Pipeline Flow
When you instantiate a pipeline with an Ultralytics model path, the following sequence executes:
-
Dependency Resolution – Ultralytics is declared as an optional extra in
pyproject.toml(ultralytics>=3.8.200). Install withuv sync --all-extrasorpip install boxmot[ultralytics]. -
Automatic Model Detection – The
is_ultralytics_model()helper (defined inboxmot/detectors/__init__.py) inspects the supplied path. When it returnsTrue,DetectorReIDPipelineinstantiates the model viaYOLO(path_or_placeholder)at lines 38–39 ofinference.py. -
Inference Execution – Calling
pipeline.predict(source)forwards toself.yolo.predict(...). The underlying UltralyticsYOLOobject handles internal preprocessing, inference, and post-processing, returning standardResultsobjects. -
Tensor Extraction – Utilities such as
extract_detections()(lines 84–99 ofinference.py) extract the bounding-box tensor fromresult.boxes.dataand convert it to a NumPy array with shape(N, 6)containing[x1, y1, x2, y2, conf, cls]. The same conversion logic exists inUltralytics.postprocess()(lines 44–53 ofultralytics.py). -
Performance Monitoring – The pipeline optionally records Ultralytics timing information via
result.speedinto aTimingStatsobject (lines 34–41). When ReID models are supplied, they are wrapped inTimedReIDModelto capture feature-extraction latency.
Because the Ultralytics detector conforms to the generic Detector API, you can swap it seamlessly with other backends such as YOLOX or RT-DETR without modifying downstream tracking code.
Running Inference with Ultralytics YOLO in BoxMOT
The YOLOInference class (alias for DetectorReIDPipeline) provides multiple interfaces for running detection, from single images to batch evaluation.
Single Image Detection
Use this pattern for real-time streaming or single-frame analysis:
from boxmot.engine.inference import YOLOInference
import cv2
# Accepts built-in model names or custom .pt checkpoints
yolo_path = "yolov8n.pt" # or "path/to/my_custom_yolo.pt"
# Initialize pipeline; device can be "cpu", "cuda:0", etc.
pipeline = YOLOInference(yolo_path, device="cpu")
# Warm-up executes a dummy inference to optimize GPU memory allocation
pipeline.warmup()
# Run detection on a BGR numpy array (OpenCV default)
image = cv2.imread("sample.jpg")
results = next(pipeline.predict(image, stream=False))
# Convert to standard NumPy detection format
detections = pipeline.extract_detections(results) # Shape: (N, 6)
print("Detections (x1, y1, x2, y2, conf, cls):")
print(detections)
Relevant source: Model instantiation at inference.py lines 31–38; extraction helper at lines 84–99.
Batch Processing for Evaluation
For dataset evaluation or offline processing, use the batch interface to amortize overhead across multiple images:
from boxmot.engine.inference import YOLOInference
import cv2
import glob
# Load image batch into memory
image_paths = glob.glob("data/images/*.jpg")
images = [cv2.imread(p) for p in image_paths]
# Initialize pipeline
pipeline = YOLOInference("yolov8s.pt", device="cpu")
pipeline.warmup()
# Process entire batch with consistent confidence and NMS thresholds
batch_results = pipeline.predict_batch(
images=images,
conf=0.3,
iou=0.6,
stream=False,
)
# Extract detections for each image
all_detections = [pipeline.extract_detections(r) for r in batch_results]
Relevant source: Batch processing logic at inference.py lines 44–55; timing aggregation at lines 84–90.
Adding ReID Models to the Pipeline
To enable appearance-based tracking, supply ReID weights alongside the YOLO model:
from boxmot.engine.inference import YOLOInference
import cv2
# Configure pipeline with both detection and ReID models
pipeline = YOLOInference(
yolo_model_path="yolov8m.pt",
reid_model_paths="reid_weights/resnet50.pt", # Accepts list of paths
device="cuda:0",
)
image = cv2.imread("sample.jpg")
result = next(pipeline.predict(image, stream=False))
# Get detection boxes
detections = pipeline.extract_detections(result)
# Extract ReID features for each detection (N x feature_dim)
features = pipeline.get_reid_features(detections[:, :4], image)
print("ReID feature shape:", features.shape)
Relevant source: ReID initialization at inference.py lines 60–85; feature extraction wrapper at lines 50–73.
Low-Level Detector Access
For custom workflows that bypass the high-level pipeline, instantiate the Ultralytics detector directly:
from boxmot.detectors.ultralytics import Ultralytics
import cv2
# Manual configuration of inference parameters
detector = Ultralytics(
path="yolov8n.pt",
device="cpu",
conf=0.25,
iou=0.45,
imgsz=640,
)
# Direct __call__ returns NumPy array (N, 6)
boxes = detector(cv2.imread("sample.jpg"))
print("Detected boxes:", boxes)
Relevant source: Detection flow implementation at ultralytics.py lines 8–57.
Key Source Files and Architecture
Understanding these files helps when debugging or extending the integration:
-
boxmot/detectors/ultralytics.py– Concrete implementation of the Ultralytics detector wrapper, handling theYOLOclass interface and tensor post-processing. -
boxmot/detectors/detector.py– Abstract base class defining theDetectorcontract, including image resolution helpers and weight loading utilities. -
boxmot/engine/inference.py– CentralDetectorReIDPipelinethat routes model instantiation, providespredictandpredict_batchmethods, and manages timing statistics. -
boxmot/detectors/__init__.py– Containsis_ultralytics_model(), the heuristic used to identify Ultralytics-compatible weight files. -
pyproject.toml– Declares theultralyticsextra dependency (ultralytics>=3.8.200) required for this integration. -
boxmot/utils/timing.py– ImplementsTimingStatsfor aggregating inference latency data from both detection and ReID stages.
Summary
- BoxMOT automatically detects Ultralytics YOLO models via
is_ultralytics_model()and instantiates them using the nativeYOLO()constructor. - No manual preprocessing is required because the
Ultralyticswrapper delegates image normalization and tensor conversion to the underlying library. - The
DetectorReIDPipeline(aliased asYOLOInference) provides unified interfaces for single-image, batch, and ReID-enhanced inference. - Detection outputs are standardized to NumPy arrays with shape
(N, 6)containing bounding boxes, confidence scores, and class IDs. - Architecture is backend-agnostic; swapping between Ultralytics YOLO, YOLOX, or RT-DETR requires only changing the model path.
Frequently Asked Questions
Does BoxMOT support custom-trained Ultralytics YOLO models?
Yes. Any valid Ultralytics .pt checkpoint—including those trained on custom datasets—works with BoxMOT. Pass the absolute or relative path to your weights file (e.g., "runs/detect/train/weights/best.pt") to YOLOInference. The is_ultralytics_model() function identifies the file format, and the pipeline loads it via YOLO(path) at lines 38–39 of inference.py.
What Ultralytics YOLO versions are compatible with BoxMOT?
BoxMOT requires ultralytics>=3.8.200 as specified in pyproject.toml. This version constraint ensures compatibility with the YOLO class API and the Results object structure used by the extract_detections() method. Newer YOLOv8, YOLOv9, and YOLOv11 models following the Ultralytics training format are supported.
How does BoxMOT handle image preprocessing for Ultralytics models?
Preprocessing is handled internally by the Ultralytics library itself. When you call pipeline.predict(image), the request forwards to self.yolo.predict(...), which executes resizing, normalization, and batching according to the model's imgsz parameter. The Ultralytics wrapper in boxmot/detectors/ultralytics.py only post-processes the output tensors in postprocess() (lines 44–53), converting result.boxes.data tensors to NumPy arrays.
Can I use BoxMOT with other detectors besides Ultralytics YOLO?
Yes. The Detector base class in boxmot/detectors/detector.py abstracts the detection backend. BoxMOT includes implementations for YOLOX and RT-DETR in addition to Ultralytics. Because all detectors implement the same __call__ interface returning (N, 6) arrays, you can substitute model paths in DetectorReIDPipeline without changing your tracking or evaluation scripts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →