Implementation:Obss Sahi GreedyNMM Postprocess
| Knowledge Sources | |
|---|---|
| Domains | Object_Detection, Computer_Vision, Postprocessing |
| Last Updated | 2026-02-08 12:00 GMT |
Overview
Concrete tool for resolving overlapping detections from sliced inference using greedy non-maximum merging provided by the SAHI library.
Description
GreedyNMMPostprocess is a callable class that takes a list of ObjectPrediction objects and returns a deduplicated list with overlapping predictions merged. It is the default postprocessing algorithm in SAHI's sliced inference pipeline.
The implementation:
- Converts ObjectPrediction list to a torch tensor via ObjectPredictionList
- Applies greedy_nmm() (class-agnostic) or batched_greedy_nmm() (per-category) to compute keep-to-merge mappings
- For each kept prediction, merges overlapping predictions using merge_object_prediction_pair() which computes weighted bounding box combination
- Returns the merged prediction list
The underlying greedy_nmm() function uses Shapely's STRtree for efficient spatial indexing, avoiding O(n^2) pairwise comparisons.
Alternative classes: NMSPostprocess (suppress-only), NMMPostprocess (full pairwise merging), LSNMSPostprocess (locality-sensitive hashing).
Usage
Use this as the postprocessing step in get_sliced_prediction(). The default postprocess_type="GREEDYNMM" instantiates this class. Configure postprocess_match_threshold (default 0.5) and postprocess_match_metric ("IOU" or "IOS").
Code Reference
Source Location
- Repository: sahi
- File: sahi/postprocess/combine.py
- Lines: L527-561 (GreedyNMMPostprocess class), L178-286 (greedy_nmm function), L448-464 (PostprocessPredictions base class)
Signature
class GreedyNMMPostprocess(PostprocessPredictions):
"""Greedy Non-Maximum Merging postprocessor.
Inherits from PostprocessPredictions which defines:
__init__(self,
match_threshold: float = 0.5,
match_metric: str = "IOU",
class_agnostic: bool = True)
"""
def __call__(
self,
object_predictions: list[ObjectPrediction],
) -> list[ObjectPrediction]:
"""Apply greedy NMM to merge overlapping predictions.
Args:
object_predictions: Combined predictions from all slices
and full-image detection.
Returns:
Deduplicated/merged list of ObjectPrediction.
"""
Import
from sahi.postprocess.combine import GreedyNMMPostprocess
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| match_threshold | float | No | Overlap threshold for merging (default 0.5) |
| match_metric | str | No | "IOU" or "IOS" (default "IOU") |
| class_agnostic | bool | No | If True, merge across categories (default True) |
| object_predictions | list[ObjectPrediction] | Yes | Combined predictions from all slices (passed to __call__) |
Outputs
| Name | Type | Description |
|---|---|---|
| return | list[ObjectPrediction] | Deduplicated/merged predictions with overlapping detections resolved |
Usage Examples
Standalone Usage
from sahi.postprocess.combine import GreedyNMMPostprocess
# Create postprocessor
postprocess = GreedyNMMPostprocess(
match_threshold=0.5,
match_metric="IOU",
class_agnostic=True,
)
# Apply to collected predictions from all slices
merged_predictions = postprocess(all_object_predictions)
print(f"Before merge: {len(all_object_predictions)}")
print(f"After merge: {len(merged_predictions)}")
Within Sliced Prediction Pipeline
from sahi.predict import get_sliced_prediction
from sahi import AutoDetectionModel
model = AutoDetectionModel.from_pretrained(
model_type="ultralytics",
model_path="yolov8n.pt",
device="cuda:0",
)
# GreedyNMM is the default postprocess_type
result = get_sliced_prediction(
image="large_image.jpg",
detection_model=model,
slice_height=640,
slice_width=640,
overlap_height_ratio=0.2,
overlap_width_ratio=0.2,
postprocess_type="GREEDYNMM", # default
postprocess_match_threshold=0.5, # default
postprocess_match_metric="IOU", # default
postprocess_class_agnostic=True, # default
)
print(f"Final predictions: {len(result.object_prediction_list)}")