roboflow/supervision · error · ValueError

Mean mask must match the image height and width

Error message

Mean mask must match the image height and width

What it means

Thrown by the fallback cv2.mean when a mask is supplied. The implementation selects pixels via boolean indexing (image[mask != 0]), which requires mask to be a 2D array exactly matching the image's (height, width). OpenCV has the same contract, but the fallback checks it explicitly.

Source

Thrown at src/supervision/_cv2/_image.py:116

) -> npt.NDArray[np.uint8]:
    """Scale, offset, take the absolute value, and saturate to uint8."""
    values = np.abs(image.astype(np.float64) * alpha + beta)
    return _cast_array_like_opencv(values, np.dtype(np.uint8))


def _mean(
    image: npt.NDArray[Any], mask: npt.NDArray[Any] | None = None
) -> tuple[float, float, float, float]:
    """Return per-channel means using OpenCV's four-value result contract."""
    if mask is None:
        selected = (
            image.reshape(-1, 1)
            if image.ndim == 2
            else image.reshape(-1, image.shape[2])
        )
    else:
        if mask.shape != image.shape[:2]:
            raise ValueError("Mean mask must match the image height and width")
        selected = image[mask != 0]
        if image.ndim == 2:
            selected = selected.reshape(-1, 1)
    if selected.size == 0:
        means = np.zeros(4, dtype=np.float64)
    else:
        means = np.zeros(4, dtype=np.float64)
        means[: selected.shape[1]] = np.mean(selected, axis=0)
    return cast(
        tuple[float, float, float, float],
        tuple(float(value) for value in means),
    )


def _resize(
    src: npt.NDArray[Any],
    dsize: tuple[int, int] | None,
    fx: float = 0,

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Resize the mask to the image dimensions: mask = cv2.resize(mask, (image.shape[1], image.shape[0])).
  2. Squeeze extra dimensions: mask = mask.reshape(image.shape[:2]) or mask.squeeze().
  3. Compute the mask from the same frame you are measuring.

Example fix

# before
mean = cv2.mean(frame, mask=seg_mask)  # seg_mask from half-res frame

# after
seg_mask = cv2.resize(seg_mask, (frame.shape[1], frame.shape[0]))
mean = cv2.mean(frame, mask=seg_mask)
Defensive patterns

Strategy: validation

Validate before calling

if mask is not None and mask.shape != image.shape[:2]:
    mask = mask.reshape(image.shape[:2]) if mask.size == image.size else cv2.resize(mask, (image.shape[1], image.shape[0]))
mean = cv2.mean(image, mask=mask)

Prevention

When it happens

Trigger: Calling cv2.mean(image, mask=mask) where mask.shape != image.shape[:2] — e.g. a 3-channel mask, a mask from a differently-sized image, or a mask with an extra batch dimension.

Common situations: Reusing a mask computed on a resized/downscaled frame (common in segmentation pipelines), passing a (H, W, 1) mask where (H, W) is expected, or passing a full-shape mask for a 3-channel image.

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/e61ea7a1f293c9d3. Report an issue: GitHub.