Difference Between `box_iou`, `box_iou_batch`, and `mask_iou_batch` in Roboflow Supervision

box_iou computes IoU for a single pair of bounding boxes and returns a scalar, box_iou_batch calculates pairwise IoU for batches of boxes returning an (N, M) matrix, and mask_iou_batch handles segmentation masks with automatic memory management for large datasets.

All three functions reside in src/supervision/detection/utils/iou_and_nms.py within the roboflow/supervision repository. They share a common purpose—measuring spatial overlap—but differ in input dimensionality, vectorization strategy, and memory handling. Each supports the OverlapMetric enum to toggle between standard IoU (Intersection over Union) and IOS (Intersection over Smaller area) calculations.

Function Comparison Overview

The primary distinction lies in what each function considers an "object" and how many comparisons it performs:

Function Input Shape Output Shape Computation Scope
box_iou Two boxes: (4,) and (4,) Scalar float Single pair comparison
box_iou_batch Two batches: (N, 4) and (M, 4) Matrix (N, M) All pairwise box combinations
mask_iou_batch Two mask sets: (N, H, W) and (M, H, W) Matrix (N, M) All pairwise mask combinations with memory chunking

box_iou – Single Pair Comparison

Use box_iou when you need to compare exactly two axis-aligned bounding boxes. Located at lines 87-112 in iou_and_nms.py, this function extracts x_min, y_min, x_max, and y_max coordinates to compute the intersection rectangle, then divides by either the union (IoU) or the smaller box area (IOS) depending on the overlap_metric parameter.

The implementation is lightweight and scalar-focused, making it ideal for debugging loops or simple threshold checks where vectorization overhead is unnecessary.

box_iou_batch – Vectorized Box Overlaps

When evaluating detection pipelines or implementing Non-Maximum Suppression (NMS), use box_iou_batch. This function accepts two NumPy arrays of shape (N, 4) and (M, 4), then leverages broadcasting ([:, None] and [None, :]) to generate the full (N, M) intersection matrix without Python loops.

According to the source code at lines 158-187, the function transposes input arrays to create 1-D coordinate views, computes intersection widths and heights via broadcasting, and returns a float32 matrix. It handles empty inputs gracefully by returning an empty (0, 0) array. This vectorized approach powers the library's box_non_max_suppression and box_non_max_merge utilities.

mask_iou_batch – Segmentation Mask Overlaps

For instance segmentation tasks, mask_iou_batch operates on binary masks rather than bounding boxes. It accepts tensors of shape (N, H, W) and (M, H, W), where H and W represent image height and width.

The implementation (lines 54-84 for the public wrapper, lines 401-452 for core logic) addresses a critical memory constraint: computing IoU for all mask pairs simultaneously can exhaust RAM. The function estimates required memory and, if it exceeds the default memory_limit of 5 GB, automatically falls back to _mask_iou_batch_split. This chunked approach processes slices of the true mask set iteratively, returning a float64 matrix. This routine underpins mask_non_max_suppression and mask merging operations.

Practical Code Examples

import numpy as np
import supervision as sv

# 1️⃣ box_iou – single pair comparison

box_a = [100, 100, 200, 200]  # x_min, y_min, x_max, y_max

box_b = [150, 150, 250, 250]
iou = sv.box_iou(box_a, box_b)
print(f"Single IoU: {iou:.3f}")  # Output: 0.143

# 2️⃣ box_iou_batch – matrix of overlaps

true_boxes = np.array([[100, 100, 200, 200], [300, 300, 400, 400]])
det_boxes = np.array([[150, 150, 250, 250], [320, 320, 420, 420]])
iou_matrix = sv.box_iou_batch(true_boxes, det_boxes)
print("Box IoU Matrix:\n", iou_matrix)

# Output: [[0.142857, 0.        ],

#          [0.        , 0.470588]]

# 3️⃣ mask_iou_batch – segmentation masks

mask_true = np.stack([np.eye(5, dtype=np.uint8), np.zeros((5, 5), dtype=np.uint8)])
mask_det = np.stack([np.eye(5, dtype=np.uint8), np.ones((5, 5), dtype=np.uint8)])
mask_matrix = sv.mask_iou_batch(mask_true, mask_det)
print("Mask IoU Matrix:\n", mask_matrix)

# Output: [[1. , 0. ],

#          [0. , 0.2]]

Summary

  • box_iou handles scalar comparisons of individual bounding boxes at lines 87-112, returning a single float value.
  • box_iou_batch provides fully vectorized pairwise IoU calculations for box batches using broadcasting (lines 158-187), returning an (N, M) float32 matrix.
  • mask_iou_batch processes binary segmentation masks with automatic memory management via chunking (lines 54-84), returning an (N, M) float64 matrix.
  • All three functions support the overlap_metric parameter to switch between IoU and IOS calculation modes.
  • Use scalar box_iou for debugging, box_iou_batch for detection metrics and NMS, and mask_iou_batch for instance segmentation evaluation.

Frequently Asked Questions

What is the difference between IoU and IOS in these functions?

IoU (Intersection over Union) divides the intersection area by the union of both boxes or masks, penalizing large non-overlapping regions. IOS (Intersection over Smaller) divides by the area of the smaller object, which is useful when you want to measure containment rather than symmetric overlap. Both metrics are controlled via the overlap_metric parameter, which accepts OverlapMetric.IOU or OverlapMetric.IOS as defined in src/supervision/detection/utils/iou_and_nms.py.

How does mask_iou_batch handle large datasets without running out of memory?

The function estimates the memory required for the full (N, M, H, W) computation. If this exceeds the memory_limit parameter (default 5 GB), it automatically triggers _mask_iou_batch_split to process the true masks in smaller chunks, accumulation results incrementally. This allows processing of arbitrarily large mask batches on memory-constrained hardware.

When should I use box_iou instead of box_iou_batch?

Use box_iou when you need to compare exactly two boxes and require a scalar return value, such as inside a Python loop with conditional breakpoints or simple threshold checks. For any operation requiring multiple comparisons—such as computing assignment costs for the Hungarian algorithm or performing Non-Maximum Suppression—use box_iou_batch to leverage vectorized NumPy operations and avoid slow Python loops.

Can these functions handle rotated or oriented bounding boxes?

No, these specific functions only support axis-aligned bounding boxes defined by [x_min, y_min, x_max, y_max]. For oriented bounding boxes, the supervision library provides separate utilities in src/supervision/detection/utils/converters.py (such as polygon_to_mask) that convert polygons to masks, which can then be processed with mask_iou_batch if pixel-level overlap is required.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →