roboflow/supervision · error · ValueError
masks_true and masks_detection must share the same (H, W); g
Error message
masks_true and masks_detection must share the same (H, W); got {masks_true.shape[1:]} and {masks_detection.shape[1:]}. What it means
Raised by sv.mask_iou_batch when the two mask batches have matching ndim=3 but different spatial dimensions — masks_true.shape[1:] != masks_detection.shape[1:]. Pairwise overlap is only defined for masks on the same pixel grid, so differing (H, W) is rejected.
Source
Thrown at src/supervision/detection/utils/iou_and_nms.py:853
```
"""
if isinstance(masks_true, CompactMask) and isinstance(masks_detection, CompactMask):
return compact_mask_iou_batch(masks_true, masks_detection, overlap_metric)
# Materialise any CompactMask that was passed alongside a dense array.
if isinstance(masks_true, CompactMask):
masks_true = np.asarray(masks_true)
if isinstance(masks_detection, CompactMask):
masks_detection = np.asarray(masks_detection)
if masks_true.ndim != 3 or masks_detection.ndim != 3:
raise ValueError(
"masks_true and masks_detection must be 3D (N, H, W); got "
f"ndim={masks_true.ndim} and ndim={masks_detection.ndim}."
)
if masks_true.shape[1:] != masks_detection.shape[1:]:
raise ValueError(
"masks_true and masks_detection must share the same (H, W); got "
f"{masks_true.shape[1:]} and {masks_detection.shape[1:]}."
)
# A single pass already handles empty inputs and avoids np.vstack([]) below.
if masks_true.shape[0] == 0 or masks_detection.shape[0] == 0:
return _mask_iou_batch_split(masks_true, masks_detection, overlap_metric)
# Peak memory of a single matmul pass: the flattened detection masks (shared
# across chunks) plus, per true-mask row, its flattened pixels and the three
# (N, M) matrices it touches (intersection, denominator and output). The
# previous (N, M, H, W) estimate overcounted by a factor of M and forced
# needless chunking now that the intersection is a matmul.
pixels = masks_true.shape[1] * masks_true.shape[2]
itemsize = 4 if pixels <= 2**24 else 8
limit_bytes = memory_limit * 1024 * 1024
detection_bytes = masks_detection.shape[0] * pixels * itemsize
per_true_row = pixels * itemsize + 3 * masks_detection.shape[0] * 8
if detection_bytes > limit_bytes > 0:View on GitHub (pinned to 7f254d9784)
Solutions
- Resize one side to the other's (H, W) before calling: e.g. cv2.resize per mask or model postprocess that maps masks back to original image size
- Ensure the model's mask postprocess returns masks at input-image resolution
- Verify shape[1:] equality with an assert before evaluation loops to catch regressions early
Example fix
# before ious = sv.mask_iou_batch(gt_masks, det_masks) # (N,720,1280) vs (M,1080,1920) # after import cv2 det_masks = np.stack([cv2.resize(m, (gt_masks.shape[2], gt_masks.shape[1]), interpolation=cv2.INTER_NEAREST) for m in det_masks]) ious = sv.mask_iou_batch(gt_masks, det_masks)
Defensive patterns
Strategy: validation
Validate before calling
import numpy as np
def assert_same_hw(masks_true, masks_detection):
assert masks_true.ndim == 3 and masks_detection.ndim == 3
assert masks_true.shape[1:] == masks_detection.shape[1:], (
f"spatial mismatch: {masks_true.shape[1:]} vs {masks_detection.shape[1:]}"
) Prevention
- Resize prediction masks back to source resolution in model postprocess
- Assert shape[1:] equality once before evaluation loops, not per pair
- Keep one canonical (H, W) in scope and resize every incoming mask batch to it
When it happens
Trigger: sv.mask_iou_batch(masks_true, masks_detection) where ground truths are e.g. (N, 720, 1280) and detections (M, 1080, 1920), or any resize applied to one side only.
Common situations: Comparing model outputs against ground truth when the model resizes inputs internally and returns masks at a different resolution; mixing masks from two different cameras/resolutions; a preprocessing resize added to one branch of an evaluation script during refactoring.
Related errors
- masks_true and masks_detection must be 3D (N, H, W); got ndi
- `is_crowd` length ({len(is_crowd)}) must match `boxes_true`
- NumPy image must have at least 2 dimensions (H, W, ...). Rec
- All KeyPoints must have the same number of keypoints per ske
- LabelMe annotation for {image_name} requires 'imageWidth' an
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/9b43a315cec1ec56.
Report an issue: GitHub.