{"record":{"id":"ae9e439ea617f52a","repo":"roboflow/supervision","slug":"hsv2bgr-conversion-requires-a-three-channel-image","errorCode":null,"errorMessage":"HSV2BGR conversion requires a three-channel image","messagePattern":"HSV2BGR conversion requires a three-channel image","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/_cv2/_color.py","lineNumber":54,"sourceCode":"        if image.dtype == np.uint8:\n            values = image.astype(np.uint32)\n            weighted = (\n                values[..., 0] * 3735\n                + values[..., 1] * 19235\n                + values[..., 2] * 9798\n                + (1 << 14)\n            ) >> 15\n            return weighted.astype(np.uint8)\n        float_values = (\n            image[..., 0].astype(np.float64) * 0.114\n            + image[..., 1].astype(np.float64) * 0.587\n            + image[..., 2].astype(np.float64) * 0.299\n        )\n        return _cast_array_like_opencv(float_values, image.dtype)\n\n    if code == _COLOR_HSV2BGR:\n        if image.ndim != 3 or image.shape[2] != 3:\n            raise ValueError(\"HSV2BGR conversion requires a three-channel image\")\n        return _hsv_to_bgr(image)\n\n    raise ValueError(f\"Unsupported color conversion code: {code}\")\n\n\ndef _hsv_to_bgr(image: npt.NDArray[Any]) -> npt.NDArray[Any]:\n    \"\"\"Convert OpenCV's 8-bit HSV representation to BGR.\"\"\"\n    values = image.astype(np.float64)\n    hue = values[..., 0] / 30.0\n    saturation = values[..., 1] / 255.0\n    value = values[..., 2] / 255.0\n\n    chroma = value * saturation\n    sector_index = np.floor(hue).astype(np.int64) % 6\n    sector = hue - np.floor(hue)\n    x = chroma * (1 - np.abs(((sector_index + sector) % 2) - 1))\n    match = value - chroma\n    zeros = np.zeros_like(chroma)","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/_cv2/_color.py#L36-L72","documentation":"HSV2BGR (used for annotator color maps) converts OpenCV's 8-bit HSV representation back to BGR and requires a 3-channel 3-D image. The fallback at src/supervision/_cv2/_color.py:54 raises when the input is not exactly (H, W, 3), since hue/saturation/value channels must all be present.","triggerScenarios":"Calling `cv2.cvtColor(img, cv2.COLOR_HSV2BGR)` with a 2-D array, an (H, W, 4) array, or a batched 4-D array on the fallback backend.","commonSituations":"Annotator/heatmap code that builds HSV images with a stray extra channel or loses a dimension via slicing; feeding arrays straight from a model without reshaping.","solutions":["Reshape to (H, W, 3): `img = img.reshape(h, w, 3)`","Slice extra channels: `img[..., :3]`","Index batched input per-image before conversion"],"exampleFix":"// before\nbgr = cv2.cvtColor(hsv_array, cv2.COLOR_HSV2BGR)  # shape (H, W, 4)\n\n// after\nbgr = cv2.cvtColor(hsv_array[..., :3], cv2.COLOR_HSV2BGR)","handlingStrategy":"type-guard","validationCode":"import numpy as np\n\ndef as_hsv_three_channel(image):\n    \"\"\"Return a (H, W, 3) HSV array for HSV2BGR conversion.\"\"\"\n    arr = np.asarray(image)\n    if arr.ndim != 3 or arr.shape[2] != 3:\n        raise ValueError(f\"HSV input must be (H, W, 3), got {arr.shape}\")\n    return arr","typeGuard":"def is_hsv_frame(image) -> bool:\n    \"\"\"HSV2BGR requires exactly (H, W, 3).\"\"\"\n    arr = np.asarray(image)\n    return arr.ndim == 3 and arr.shape[2] == 3","tryCatchPattern":null,"preventionTips":["Build HSV images with np.zeros((h, w, 3), dtype=np.uint8) so the shape is exact","Assert the shape after slicing/manipulating HSV arrays in annotator code"],"tags":["cv2-fallback","color-conversion","hsv","shape-validation"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}