import xarray as xr
# Not exactly part of the public API, but they seem to be open to it?
# https://github.com/pydata/xarray/issues/5081
from xarray.core.indexing import LazilyIndexedArray
from ..array._bayer2rgb_array import BayerToGrayArray, RGBToGrayArray
from ._properties import get_bayer_pattern, get_chroma
def _define_starting_index(bayer_pattern, channel):
# channel should be a string of
# 'red', 'green', or 'blue'
if channel == 'green1':
index = bayer_pattern.rfind(channel[0])
else:
index = bayer_pattern.find(channel[0])
return (index // 2, index % 2)
[docs]
def bayer_dataset_to_single_channel(dataset, color):
"""Extract a fixed color pixel from data acquired with CFA sensors.
Given data acquired with a sensor contained a color filter array, this
function extracts a single monochrome pixel from the array.
This function can help reduce the data analysis load and speed up
algorithms that work will with monochromatic images.
While a standard Bayer pattern has one red pixel, and one blue pixel, it
contains two green pixels. We denote the green pixel on the first row
as the ``'green0'`` pixel, and the green pixel on the second row as the
``'green1'`` pixel. Here ``'green'`` is shorthand for ``'green0'``.
Parameters
----------
dataset: mcam_dataset
Dataset containing MCAM images. The dataset must contain the
``bayer_pattern`` that describes the pixel ordering in the
color filter array.
color:
Color to extract. Must be one of:
``['red', 'green', 'blue', 'green0', 'green1']``
Returns
-------
dataset:
The returned dataset no longer contains the ``bayer_pattern`` variable
to indicate that it has been converted to that of a monochromatic
image.
Notes
-----
The images in the dataset must all have been acquired with the same pattern
for the color filter array.
"""
from ._properties import get_bayer_pattern
allowed_colors = ['red', 'green', 'blue', 'green0', 'green1']
if color not in allowed_colors:
raise ValueError(f"Color must be in {allowed_colors}. Got {color}.")
bayer_pattern = get_bayer_pattern(dataset)
y_start, x_start = _define_starting_index(bayer_pattern, color)
# drop creates a shallow copy
dataset = dataset.drop_vars('bayer_pattern')
dataset = dataset.isel({'y': slice(y_start, None, 2),
'x': slice(x_start, None, 2)})
return dataset
[docs]
def bayer_dataset_to_rgb(dataset):
"""Convert a dataset acquired with a bayer sensor to an RGB dataset.
Given data acquired with a sensor contained a color filter array, this
converts the raw data to that of an RGB image.
Parameters
----------
dataset: mcam_dataset
Dataset containing MCAM images. The dataset must contain the
``bayer_pattern`` that describes the pixel ordering in the
color filter array. The images variable will contain a new dimension
labeled with `'rgb'` with dimension of 3.
Returns
-------
dataset:
The returned dataset no longer contains the ``bayer_pattern`` variable
to indicate that it has been converted to that of a monochromatic
image.
"""
# TODO consolidate the methods:
# * to_rgb
# * bayer_dataset_to_rgb
from ._core import to_rgb
return to_rgb(dataset)
[docs]
def bayer_dataset_to_grayscale(dataset, *, gray_vector=None):
"""Convert a dataset acquired with a bayer sensor to a grayscale dataset.
Given data acquired with a sensor contained a color filter array, this
converts the raw data to that of an RGB image.
Parameters
----------
dataset: mcam_dataset
Dataset containing MCAM images. The dataset must contain the
``bayer_pattern`` that describes the pixel ordering in the
color filter array. The ``images`` variable will contain
the new grayscale dataset. All other metadata will be retained.
Returns
-------
dataset:
The returned dataset no longer contains the ``bayer_pattern`` variable
to indicate that it has been converted to that of a monochromatic
image.
"""
# Before merging, lets make sure that we resolve
# https://gitlab.com/ramonaoptics/mcam/python-owl/-/issues/137
if get_chroma(dataset) != "bayer":
raise ValueError('Can only convert raw bayer data to grayscale.')
bayer_pattern = get_bayer_pattern(dataset)
# FastPath for opencv
grayscale_data = BayerToGrayArray(
dataset.images.variable,
bayer_pattern,
gray_vector=gray_vector,
)
grayscale_data = LazilyIndexedArray(grayscale_data)
images = xr.DataArray(
data=grayscale_data,
dims=dataset.images.dims,
attrs=dataset.images.attrs.copy(),
)
# Shallow copy to not mutate the user's data
dataset = dataset.copy(deep=False)
dataset['images'] = images
if 'bayer_pattern' in dataset:
# Removing the bayer pattern indicates that it is a color image???
del dataset['bayer_pattern']
return dataset
[docs]
def rgb_dataset_to_grayscale(dataset, *, gray_vector=None):
"""Convert a debayered rgb dataset to a grayscale dataset.
Parameters
----------
dataset: mcam_dataset
Dataset containing MCAM images. The dataset must contain the
dimension ``rgb``. The ``images`` variable will contain
the new grayscale dataset. All other metadata will be retained.
gray_vector: tuple
A 3-tuple of floats that describes the weights of the red, green, and
blue channels in the conversion to grayscale. The default values are
the ITU-R BT.709-1 standard.
Returns
-------
dataset:
The returned dataset no longer contains the ``rgb`` dimension
indicating that it has been converted to that of a grayscale
image.
"""
if get_chroma(dataset) != "rgb":
raise ValueError('Can only convert RGB data to grayscale.')
grayscale_data = RGBToGrayArray(dataset.images.variable, gray_vector=gray_vector)
grayscale_data = LazilyIndexedArray(grayscale_data)
new_dims = [d for d in dataset.images.dims if d != 'rgb']
new_attrs = [a for a in dataset.images.attrs if a != 'rgb']
images = xr.DataArray(
data=grayscale_data,
dims=new_dims,
attrs=new_attrs,
)
# Shallow copy to not mutate the user's data
dataset = dataset.copy(deep=False).drop_dims('rgb')
dataset['images'] = images
return dataset