ensemble-boxes merges detector outputs with four fusion methods
Set of methods to ensemble boxes from different object detection models, including implementation of "Weighted boxes fusion (WBF)" method.
At a glance
- What is it?
- ensemble-boxes is a Python package that combines bounding boxes from several object detection models, implementing non-maximum suppression, Soft-NMS, non-maximum weighted and weighted boxes fusion, plus 1D, 3D, rotated and quadrangle variants. It suits researchers and engineers assembling detector ensembles, and it expects normalized coordinates and a consistent label space.
- Who is it for?
- ensemble-boxes fits teams combining several detection models into one set of boxes, and researchers who want weighted boxes fusion and its variants in a few lines of readable code with benchmark files for comparison. It does not fit a pipeline that works in pixel coordinates without normalizing first, nor one whose models disagree about class indices.
- 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 30 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 November 7, 2026, and from our analysis. They are not legal advice.
Star history
- ZFTurbo/Weighted-Boxes-Fusion1,832 ★ · +0
| Repository | 2026-10-17 | 2026-11-07 |
|---|---|---|
| ZFTurbo/Weighted-Boxes-Fusion | 1.8k | 1.8k |
0 Stars in the last 21 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Four ways to merge the same overlapping boxes
Object detection ensembles produce overlapping boxes from different models, and merging them is a decision with several defensible answers. This package implements four of them side by side, which is the reason to use it rather than a single function.
Non-maximum suppression is the baseline. Soft-NMS replaces the hard suppression of a neighbouring box with a decay of its score, and the readme cites the 2017 arXiv paper for it. Non-maximum weighted follows the ICCV 2017 workshop paper, weighting the surviving boxes by the model weights instead of discarding them. Weighted boxes fusion is the method the project is best known for, described in the 2020 arXiv revision and published in Image and Vision Computing, and the readme states plainly that it gives better results compared to the others.
Having all four in one place is what makes the package useful for research rather than for production. The benchmarks are set up for exactly this comparison, with a benchmark for the Open Images dataset using 5 models, a benchmark for COCO using 10 models, and a benchmark for an NLP dataset using 10 models as an example of the one-dimensional variant. Each benchmark directory in the repository has its own readme describing the setup, so the comparison is reproducible rather than a claim in a blog post.
The audience is therefore the person who has two or more detectors and needs to know what the fusion does to their numbers before they commit to it in a pipeline. The code is MIT licensed, the language is Python 3 with Numpy and Numba as the requirements, and the paper carries a DOI through Zenodo.
The API is four lists and four parameters
The interface is deliberately plain, and understanding it takes a minute. Coordinates for boxes are expected to be normalized, in the range from 0 to 1, and the order of a box is x1, y1, x2, y2. There are three parallel lists, one per model, plus a list of weights:
The first model in the readme example predicts 5 boxes and the second predicts 4, with confidence scores of 0.9, 0.8, 0.2, 0.4 and 0.7 for the first model and 0.5, 0.8, 0.7 and 0.3 for the second. The labels are class indices, 0 and 1, for each model. The weights are set to 2 for the first model and 1 for the second, the intersection over union threshold used to decide that two boxes match is 0.5, and boxes with a confidence below 0.0001 are skipped.
Every method then takes the same arguments:
from ensemble_boxes import *
boxes, scores, labels = nms(boxes_list, scores_list, labels_list, weights=weights, iou_thr=iou_thr)The call returns the fused boxes, their scores and their labels, and the same call shape works for soft_nms, non_maximum_weighted and weighted_boxes_fusion, with soft_nms taking an extra sigma parameter for the score decay and non_maximum_weighted taking a skip_box_thr argument.
Two conventions are worth internalising because they are the usual source of silent errors. The coordinates must already be normalized, so any pipeline working in pixels has to divide before calling. And the label arrays must use the same class mapping across models, otherwise a fused box ends up with a label that means something different depending on which model it came from.
One model is a valid call, and the variants widen the scope
The functions are not restricted to ensembles. A single model with many overlapping detections has the same problem, and the readme shows that case explicitly:
from ensemble_boxes import *
# Merge boxes for single model predictions
boxes, scores, labels = weighted_boxes_fusion([boxes_list], [scores_list], [labels_list], weights=None, method=method, iou_thr=iou_thr, thresh=thresh)The single model is expressed as a list of one, the weights are None, and the method is passed as an argument so the same function can run any of the four. That is a small design decision with a large convenience payoff, since one call site can switch between NMS and weighted boxes fusion without touching the surrounding code.
Beyond the two-dimensional case, the package covers four other geometries. weighted_boxes_fusion_3d handles 3D boxes, with an example in examples/example_3d.py. weighted_boxes_fusion_1d handles 1D line segments, and the readme records that this variant was reported as useful for named-entity recognition style NLP problems, with a Kaggle discussion linked. weighted_boxes_fusion_rotated handles oriented boxes, where each box is a centre, a size and an angle. weighted_boxes_fusion_quadrangle handles the alternative 4-vertex declaration used by annotation formats such as DOTA and HRSC2016, where all 8 coordinates are normalized and the vertices may arrive in any winding because they are re-ordered canonically before fusion.
The examples directory carries a matching script for each variant, so the geometry coverage is not a claim but a set of runnable files.
Rotated boxes need one scale for both axes
The rotated variant has a constraint that is easy to miss and expensive to debug, and the readme gives it its own note. Each rotated box is a tuple of cx, cy, w, h and an angle, with cx, cy, w and h normalized to the range from 0 to 1 and the angle given in degrees using the le90 convention from MMRotate, in the range from minus 90 up to but not including 90, with w always the longer edge.
The constraint is that the normalization must use the same scale for both axes. The readme says to divide cx, cy, w and h in pixels by max(image_width, image_height), or to use a square image. The reason is geometric: normalizing x by the width and y by the height separately turns a rotated rectangle into a parallelogram and changes its angle, so the fused boxes come back with a wrong orientation even though every coordinate looks plausible.
Getting back to pixels uses the same scale, multiplying the fused cx, cy, w and h by it. The instruction is precise enough that a pipeline can be checked against it, which is more than most libraries give you for oriented boxes, and it also explains why the notebooks and the dedicated example file both exist for this variant.
The paper, the citation and the adoptions list
The project asks you to cite the method rather than the code. The readme provides a BibTeX entry for the Image and Vision Computing paper by Solovyev, Wang and Gabruseva, and points at the arXiv version, updated in August 2020, and at the Elsevier page. The method is what other people will cite when they write about their own ensemble, and the repository also carries a document listing notable projects that have used it, which is a reasonable way to gauge whether the approach has become a standard part of detector ensembles.
The package on PyPI is ensemble-boxes, and the installation instruction is a single line:
pip install ensemble-boxesVersioning is where the repository tells a slightly awkward story. The release list shows v1.0.8 tagged in March 2022 with the note about benchmark files for the NLP problem, and earlier tags in 2020, while the packaging metadata in setup.py declares version 1.0.9. The last push was on 2026-10-09, so the tree is being worked on even though the tags are years old, and the package metadata and the last release are not the same number. Anyone citing a result should say which one they used.
On the licence, the repository is MIT, which matters for a research component that ends up inside a commercial product. The remaining dependency question is the short requirements list, Numpy and Numba, with the dev environment script creating a virtual environment named wbf and the tests run with pytest:
source setup_dev_env.shpython -m pytest tests/Where a framework's own NMS fits better
The alternative is the non-maximum suppression that comes with the framework you already use, and the difference in approach is about integration rather than quality.
A built-in NMS call lives in the same process as the detector, takes the detector's own output format, and returns the format the rest of the pipeline expects. There is no normalization step to forget, no label mapping to reconcile, and no separate package in the dependency list. For a single model with a modest number of overlapping boxes, that integration advantage is usually worth more than the quality difference between suppression methods.
This package wins in the opposite situation. If you are running several models, comparing fusion strategies, or working with a geometry the framework does not support, the value of having four well-known methods, 1D, 3D, rotated and quadrangle variants, and benchmark files that let you measure the difference is considerable. The readme is explicit that weighted boxes fusion gives better results than the alternatives, and the benchmark directories exist so you can check that claim on your own data rather than take it on faith.
The hybrid is common in practice. Keep the framework's suppression for the single model path where the integration is free, and use this package for the multi-model case where the comparison actually matters. The cost of that split is two code paths and a normalization boundary to keep honest.
A second alternative is to write the fusion yourself, which some groups do because the weighted boxes fusion algorithm is a paper-length description rather than a large codebase. The argument for using the package is the variants, the benchmarks and the fact that the rotating and quadrangle geometry handling has edge cases that are easy to get wrong.
Editorial conclusion
ensemble-boxes fits teams combining several detection models into one set of boxes, and researchers who want weighted boxes fusion and its variants in a few lines of readable code with benchmark files for comparison. It does not fit a pipeline that works in pixel coordinates without normalizing first, nor one whose models disagree about class indices. Verify first that your label arrays use the same class mapping, that the rotated variant is fed one scale for both axes, and that the version you install is the one your results were measured against, since the package version and the last tagged release differ.
Frequently asked questions
How do I install ensemble-boxes?
The package is published on PyPI as ensemble-boxes and installs with pip install ensemble-boxes. It needs Python 3 with Numpy and Numba, and for development the repository ships a setup script that creates a virtual environment named wbf.
What coordinate format does ensemble-boxes expect?
Box coordinates are expected to be normalized in the range from 0 to 1, in the order x1, y1, x2, y2. The rotated variant needs cx, cy, w and h normalized by the same scale for both axes, which the readme gives as max(image_width, image_height).
Which fusion methods does ensemble-boxes implement?
It implements non-maximum suppression, Soft-NMS, non-maximum weighted and weighted boxes fusion, and the weighted boxes fusion method is also available in 1D, 3D, rotated and quadrangle variants through separate functions.
Can ensemble-boxes merge boxes from a single model?
Yes. The readme shows the single model case expressed as a list of one, with weights set to None and the method passed as an argument, so the same function can apply any of the four methods to one model's predictions.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/zfturbo-weighted-boxes-fusion)Star history chart for your README
[](https://hysenlabs.com/projects/zfturbo-weighted-boxes-fusion)Was this useful?