Source code for spacr.image_colors

"""Colour-order boundaries for OpenCV.

spaCR's in-memory colour contract is RGB (or RGBA).  OpenCV is the one major
dependency that decodes and encodes three-channel images as BGR, so conversions
belong directly beside ``imread``/``imwrite`` rather than in plotting or model
code.  Grayscale arrays pass through unchanged.
"""
from __future__ import annotations

from os import PathLike
from typing import Optional, Union

import numpy as np

PathValue = Union[str, PathLike[str]]


[docs] def cv2_to_rgb(image: Optional[np.ndarray]) -> Optional[np.ndarray]: """Convert an OpenCV BGR/BGRA array to spaCR's RGB/RGBA contract. :param image: decoded OpenCV array, grayscale array, or ``None``. :returns: contiguous RGB/RGBA data for three- or four-channel inputs; ``None``, grayscale, and other channel counts pass through unchanged. """ if image is None: return None arr = np.asarray(image) if arr.ndim != 3: return arr if arr.shape[-1] == 3: return np.ascontiguousarray(arr[..., ::-1]) if arr.shape[-1] == 4: return np.ascontiguousarray(arr[..., [2, 1, 0, 3]]) return arr
[docs] def rgb_to_cv2(image: np.ndarray) -> np.ndarray: """Convert an RGB/RGBA array only for an immediate OpenCV write call. :param image: spaCR RGB/RGBA array, or a grayscale array to pass through. :returns: contiguous BGR/BGRA data for three- or four-channel inputs; grayscale and other channel counts pass through unchanged. """ arr = np.asarray(image) if arr.ndim != 3: return arr if arr.shape[-1] == 3: return np.ascontiguousarray(arr[..., ::-1]) if arr.shape[-1] == 4: return np.ascontiguousarray(arr[..., [2, 1, 0, 3]]) return arr
[docs] def read_image_rgb(path: PathValue, flags: int = -1) -> Optional[np.ndarray]: """Read with OpenCV and immediately return RGB/RGBA in memory. :param path: image path accepted by OpenCV. :param flags: OpenCV read mode; ``-1`` preserves the stored dtype and alpha channel. :returns: RGB/RGBA or grayscale image data, or ``None`` when OpenCV cannot read the path. """ import cv2 return cv2_to_rgb(cv2.imread(str(path), flags))
[docs] def write_image_rgb(path: PathValue, image: np.ndarray, params=None) -> bool: """Write an RGB/RGBA array through OpenCV without leaking BGR internally. :param path: output image path passed to OpenCV. :param image: spaCR RGB/RGBA array, converted immediately before encoding. :param params: optional OpenCV encoder parameter sequence. :returns: whether OpenCV encoded and wrote the image successfully. """ import cv2 encoded = rgb_to_cv2(image) if params is None: return bool(cv2.imwrite(str(path), encoded)) return bool(cv2.imwrite(str(path), encoded, params))