import cv2
import numpy as np
import xarray as xr
from dask import array as da
from ..upstream.skimage.color import bayer2rgb as sk_bayer2rgb
[docs]
def bayer2rgba(image, bayer_pattern: str='rggb', output_array=None):
"""Convert a raw image from a sensor with a Bayer filter to an RGBA image.
Parameters
----------
image: ArrayLike[N, M]
The image to be converted. ``N``, ``M`` should be even.
bayer_pattern:
The bayer pattern of the sensor. Should be one of
``['rggb', 'bggr', 'grbg', 'gbrg']``.
output_array: ArrayLike[N, M, 4] or None
If OpenCV2 is installed, this specifies the output array of the
operation. Without the OpenCV backend, this parameter can only
take the value of None.
If provided, this should be a C contiguous array.
Returns
-------
output_array: ArrayLike[N, M, 4]
The image converted to RGBA format.
"""
dtype_in = np.dtype(image.dtype)
if dtype_in in [np.dtype(np.uint8), np.dtype(np.uint16)]:
return cv_bayer2rgba(image, bayer_pattern, output_array)
else:
raise NotImplementedError("We don't support conversion to rgba "
"for your dtype.")
[docs]
def bayer2rgb(image, bayer_pattern='rggb', output_array=None):
"""Convert a raw image from a sensor with a Bayer filter to an RGB image.
Parameters
----------
image: ArrayLike[N, M]
The image to be converted. ``N``, ``M`` should be even.
bayer_pattern:
The bayer pattern of the sensor. Should be one of
``['rggb', 'bggr', 'grbg', 'gbrg']``.
output_array: ArrayLike[N, M, 3] or None
If OpenCV2 is installed, this specifies the output array of the
operation. Without the OpenCV backend, this parameter can only
take the value of None.
If provided, this should be a C contiguous array.
Returns
-------
output_array: ArrayLike[N, M, 3]
The image converted to RGBA format.
"""
if isinstance(image, xr.DataArray):
image = image.data
dtype_in = np.dtype(image.dtype)
if dtype_in in [np.dtype(np.uint8), np.dtype(np.uint16)]:
return cv_bayer2rgb(image, bayer_pattern, output_array)
else:
if output_array is not None:
raise ValueError('We only support creating a new array '
'for images not of type uint8 or uint16')
return sk_bayer2rgb(image, bayer_pattern)
[docs]
def bayer2gray(image, bayer_pattern, output_array=None):
"""Convert an image from a sensor with a Bayer filter to a grayscale image.
Parameters
----------
image: ArrayLike[N, M]
The image to be converted. ``N``, ``M`` should be even.
bayer_pattern:
The bayer pattern of the sensor. Should be one of
``['rggb', 'bggr', 'grbg', 'gbrg']``.
output_array: ArrayLike[N, M] or None
If OpenCV2 is installed, this specifies the output array of the
operation. Without the OpenCV backend, this parameter can only
take the value of None.
If provided, this should be a C contiguous array.
Returns
-------
output_array: ArrayLike[N, M]
The image converted to grayscale format.
"""
# See details about the colorspace that opencv uses
# https://github.com/opencv/opencv/issues/18813#issuecomment-2227104595
dtype_in = np.dtype(image.dtype)
if dtype_in not in [np.dtype(np.uint8), np.dtype(np.uint16)]:
raise RuntimeError("We only support bayer to grayscale for uint8 and uint16 images")
return cv_bayer2gray(image, bayer_pattern, output_array)
def cv_bayer2gray(image, bayer_pattern, output_array=None):
if image.shape[0] % 2 != 0 or image.shape[1] % 2 != 0:
raise ValueError(
"Image must have an even number of rows and columns.")
if bayer_pattern == 'rggb':
cv_pattern = cv2.COLOR_BAYER_BG2GRAY
elif bayer_pattern == 'bggr':
cv_pattern = cv2.COLOR_BAYER_RG2GRAY
elif bayer_pattern == 'grbg':
cv_pattern = cv2.COLOR_BAYER_GB2GRAY
elif bayer_pattern == 'gbrg':
cv_pattern = cv2.COLOR_BAYER_GR2GRAY
else:
raise ValueError(f'Unknown pattern {bayer_pattern}.')
image = np.asarray(image)
return cv2.cvtColor(image, cv_pattern, output_array)
def cv_bayer2rgb(image, bayer_pattern='rggb', output_array=None):
if image.shape[0] % 2 != 0 or image.shape[1] % 2 != 0:
raise ValueError(
"Image must have an even number of rows and columns.")
if bayer_pattern == 'rggb':
# cv_pattern = cv2.COLOR_BAYER_BG2RGB_EA
cv_pattern = cv2.COLOR_BAYER_BG2RGB
elif bayer_pattern == 'bggr':
# cv_pattern = cv2.COLOR_BAYER_RG2RGB_EA
cv_pattern = cv2.COLOR_BAYER_RG2RGB
elif bayer_pattern == 'grbg':
# cv_pattern = cv2.COLOR_BAYER_GB2RGB_EA
cv_pattern = cv2.COLOR_BAYER_GB2RGB
elif bayer_pattern == 'gbrg':
# cv_pattern = cv2.COLOR_BAYER_GR2RGB_EA
cv_pattern = cv2.COLOR_BAYER_GR2RGB
else:
raise ValueError(f'Unknown pattern {bayer_pattern}.')
image = np.asarray(image)
return cv2.cvtColor(image, cv_pattern, output_array)
def cv_bayer2rgba(image, bayer_pattern='rggb', output_array=None):
# Note this function needs https://github.com/opencv/opencv/pull/12465
# I'm trying to get it merged into conda-forge
# https://github.com/conda-forge/opencv-feedstock/pull/125
if image.shape[0] % 2 != 0 or image.shape[1] % 2 != 0:
raise ValueError(
"Image must have an even number of rows and columns.")
if bayer_pattern == 'rggb':
cv_pattern = cv2.COLOR_BAYER_BG2RGBA
elif bayer_pattern == 'bggr':
cv_pattern = cv2.COLOR_BAYER_RG2RGBA
elif bayer_pattern == 'grbg':
cv_pattern = cv2.COLOR_BAYER_GB2RGBA
elif bayer_pattern == 'gbrg':
cv_pattern = cv2.COLOR_BAYER_GR2RGBA
else:
raise ValueError(f'Unknown pattern {bayer_pattern}.')
image = np.asarray(image)
return cv2.cvtColor(image, cv_pattern, output_array)
def da_bayer2rgb(image, bayer_pattern):
this_bayer2rgb = da.gufunc(bayer2rgb,
signature='(m,n),()->(m,n,rgb)',
output_dtypes=image.dtype,
output_sizes={'rgb': 3},
# allow_rechunk=True,
vectorize=True)
# Maybe I should just allow rechunking
# Allow rechunk isn't smart enough
bayer_pattern = da.from_array(bayer_pattern, chunks=image.chunks[:-2])
return this_bayer2rgb(image, bayer_pattern)
def da_bayer2rgba(image, bayer_pattern):
this_bayer2rgba = da.gufunc(bayer2rgba,
signature='(m,n),()->(m,n,rgba)',
output_dtypes=image.dtype,
output_sizes={'rgba': 4},
# allow_rechunk=True,
vectorize=True)
# Maybe I should just allow rechunking
# Allow rechunk isn't smart enough
bayer_pattern = da.from_array(bayer_pattern, chunks=image.chunks[:-2])
return this_bayer2rgba(image, bayer_pattern)