roboflow/supervision · error · ValueError

Connected-component input must be a two-dimensional image

Error message

Connected-component input must be a two-dimensional image

What it means

Connected-component labeling is inherently a 2D operation; the fallback validates that the input array has exactly two dimensions before converting it to a boolean mask. 3D arrays (video volumes, multi-channel images) or 1D/0D arrays are rejected.

Source

Thrown at src/supervision/_cv2/_components.py:15

"""Private connected-component and mask-topology fallbacks."""

from __future__ import annotations

from typing import Any, cast

import numpy as np
import numpy.typing as npt


def _validate_binary_image(image: npt.NDArray[Any]) -> npt.NDArray[np.bool_]:
    """Validate and normalize a two-dimensional component image."""
    values = np.asarray(image)
    if values.ndim != 2:
        raise ValueError("Connected-component input must be a two-dimensional image")
    return cast(npt.NDArray[np.bool_], values != 0)


def _label(
    image: npt.NDArray[Any], connectivity: int
) -> tuple[int, npt.NDArray[np.int32]]:
    """Label foreground pixels with the requested four- or eight-way topology."""
    if connectivity not in (4, 8):
        raise ValueError("Only 4- and 8-connectivity are supported")

    from scipy import ndimage

    structure = ndimage.generate_binary_structure(2, 1 if connectivity == 4 else 2)
    labels, count = ndimage.label(_validate_binary_image(image), structure=structure)
    return int(count), np.ascontiguousarray(labels, dtype=np.int32)


def _connected_components(

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Convert color input to grayscale first: gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY).
  2. Squeeze channel/batch dims: mask = mask.reshape(h, w) or mask.squeeze().
  3. Loop over frames/batch items and label each 2D slice separately.

Example fix

# before
count, labels = cv2.connectedComponents(bgr_image)  # (H, W, 3)

# after
gray = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2GRAY)
count, labels = cv2.connectedComponents(gray)
Defensive patterns

Strategy: validation

Validate before calling

img2d = image if image.ndim == 2 else image.reshape(image.shape[:2])
count, labels = cv2.connectedComponents(img2d)

Type guard

def is_labelable(img: np.ndarray) -> bool:
    return np.asarray(img).ndim == 2

Prevention

When it happens

Trigger: Calling cv2.connectedComponents on a (H, W, 3) BGR image, a (T, H, W) video stack, or a squeezed-to-1D mask.

Common situations: Forgetting cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) before labeling; passing a batch of masks at once; masks with a spurious trailing channel dimension (H, W, 1).

Related errors


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