roboflow/supervision · error · TypeError

image must be uint8, got {image.dtype}. Convert with image.a

Error message

image must be uint8, got {image.dtype}. Convert with image.astype(np.uint8) before calling show().

What it means

Raised by ImageWindow.show() in supervision.utils.image_window when the input array's dtype is not np.uint8. The Tk-based display path converts the array straight to a Pillow image, which requires 8-bit data; float arrays (common after model preprocessing) would render as garbage or fail inside Pillow, so the dtype is checked up front with an actionable message.

Source

Thrown at src/supervision/utils/image_window.py:108

    def show(self, image: npt.NDArray[np.uint8]) -> None:
        """Display a BGR, grayscale, or BGRA frame in the window.

        The image is scaled to fit the current window dimensions. Aspect ratio is
        preserved unless `keep_aspect_ratio=False`. Resizing the window rescales live.
        Args:
            image: uint8 numpy array. Accepted shapes:
                - ``(H, W)`` — grayscale
                - ``(H, W, 3)`` — BGR (OpenCV convention; channels are swapped
                  to RGB before display)
                - ``(H, W, 4)`` — BGRA (channels reordered to RGBA)

        Raises:
            TypeError: If `image.dtype` is not `uint8`.
            ValueError: If `image` is not 2-D or 3-D with 3 or 4 channels.
        """
        if image.dtype != np.uint8:
            raise TypeError(
                f"image must be uint8, got {image.dtype}. "
                "Convert with image.astype(np.uint8) before calling show()."
            )
        self._pil_image = _bgr_to_pil(image)
        self._ensure_window()
        self._update_display()
        self._root.update_idletasks()
        self._root.update()

    def wait_key(self, delay_ms: int = 0) -> str | None:
        """Wait for a keypress and return its name.

        Args:
            delay_ms: How long to wait in milliseconds. ``0`` blocks until a
                key is pressed. Positive values poll for up to `delay_ms` ms
                and return ``None`` if no key arrives in time.

        Returns:

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Scale floats back to range then cast: (img * 255).clip(0, 255).astype(np.uint8).
  2. For arbitrary floats use cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8).
  3. Convert integer types directly: img.astype(np.uint8) only if values already span 0-255.
  4. Keep a uint8 copy of the original frame for display alongside the float working copy.

Example fix

// before
window.show(frame / 255.0)  # float64 -> TypeError

// after
window.show((frame / 255.0 * 255).clip(0, 255).astype(np.uint8))
Defensive patterns

Strategy: type-guard

Validate before calling

def ensure_uint8(img: np.ndarray) -> np.ndarray:
    if img.dtype == np.uint8:
        return img
    if np.issubdtype(img.dtype, np.floating):
        return (img * 255 if img.max() <= 1.0 else img).clip(0, 255).astype(np.uint8)
    return img.astype(np.uint8)

window.show(ensure_uint8(image))

Type guard

def is_uint8_image(image: np.ndarray) -> bool:
    return image.dtype == np.uint8

Prevention

When it happens

Trigger: Calling window.show(image) with a float32/float64 array (e.g. normalized 0-1 images, model outputs, cv2.resize on floats); uint16 medical/scientific imagery; boolean masks.

Common situations: Displaying frames that went through normalization (image / 255.0); annotator outputs assumed to stay uint8 but a preprocessing step cast them; stacking with np.mean producing float; feeding depth maps.

Related errors


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