roboflow/supervision · error · ValueError
BGR/RGB conversion requires a three-channel image
Error message
BGR/RGB conversion requires a three-channel image
What it means
BGR<->RGB conversion is a channel reversal (`image[..., ::-1]`) and only makes sense for 3-channel images. The fallback at src/supervision/_cv2/_color.py:25 raises when `image.ndim != 3 or image.shape[2] != 3` — e.g. passing an RGBA (4-channel) image, a grayscale 2-D image, or a batched (N, H, W, 3) array.
Source
Thrown at src/supervision/_cv2/_color.py:25
import numpy as np
import numpy.typing as npt
from supervision._cv2._common import _cast_array_like_opencv
from supervision._cv2.constants import (
_COLOR_BGR2GRAY,
_COLOR_BGR2RGB,
_COLOR_GRAY2BGR,
_COLOR_HSV2BGR,
_COLOR_RGB2BGR,
)
def _cvt_color(image: npt.NDArray[Any], code: int) -> npt.NDArray[Any]:
"""Convert the BGR, RGB, grayscale, and 8-bit HSV formats used by Supervision."""
if code in (_COLOR_BGR2RGB, _COLOR_RGB2BGR):
if image.ndim != 3 or image.shape[2] != 3:
raise ValueError("BGR/RGB conversion requires a three-channel image")
return np.ascontiguousarray(image[..., ::-1])
if code == _COLOR_GRAY2BGR:
if image.ndim != 2:
raise ValueError("GRAY2BGR conversion requires a two-dimensional image")
return np.repeat(image[..., np.newaxis], 3, axis=2)
if code == _COLOR_BGR2GRAY:
if image.ndim != 3 or image.shape[2] != 3:
raise ValueError("BGR2GRAY conversion requires a three-channel image")
if image.dtype == np.uint8:
values = image.astype(np.uint32)
weighted = (
values[..., 0] * 3735
+ values[..., 1] * 19235
+ values[..., 2] * 9798
+ (1 << 14)
) >> 15View on GitHub (pinned to 7f254d9784)
Solutions
- Slice to 3 channels first: `img = img[..., :3]` for RGBA
- For grayscale input use COLOR_GRAY2BGR first if you need 3 channels
- Index the batch dimension for 4-D arrays: `images[i]`
Example fix
// before rgb = cv2.cvtColor(rgba_frame, cv2.COLOR_BGR2RGB) # shape (H, W, 4) // after rgb = cv2.cvtColor(rgba_frame[..., :3], cv2.COLOR_BGR2RGB)
Defensive patterns
Strategy: type-guard
Validate before calling
import numpy as np
def as_three_channel(image):
"""Return a (H, W, 3) array for channel-swap conversions."""
arr = np.asarray(image)
if arr.ndim == 2:
arr = np.repeat(arr[..., None], 3, axis=2)
elif arr.ndim == 3 and arr.shape[2] > 3:
arr = arr[..., :3]
if arr.ndim != 3 or arr.shape[2] != 3:
raise ValueError(f"expected (H, W, 3), got {arr.shape}")
return arr Type guard
def is_three_channel(image) -> bool:
"""BGR/RGB conversion requires exactly (H, W, 3)."""
arr = np.asarray(image)
return arr.ndim == 3 and arr.shape[2] == 3 Prevention
- Slice alpha away after IMREAD_UNCHANGED loads
- Standardize frames to 3 channels at ingestion so downstream cvtColor calls are safe
When it happens
Trigger: `cv2.cvtColor(img, cv2.COLOR_BGR2RGB)` on an RGBA image loaded with IMREAD_UNCHANGED, a 2-D grayscale array, or a 4-D batched tensor converted to ndarray.
Common situations: PNG with alpha channel loaded via `cv2.imread(path, cv2.IMREAD_UNCHANGED)`; webcams that yield RGBA; model preprocessing that assumes 3 channels receiving grayscale input.
Related errors
- GRAY2BGR conversion requires a two-dimensional image
- BGR2GRAY conversion requires a three-channel image
- HSV2BGR conversion requires a three-channel image
- Drawing points must have shape (N, 2) or (N, 1, 2)
- Contour input must be a two-dimensional image
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/641bab306ac687ad.
Report an issue: GitHub.