import numpy as np
valid_bayer_patterns = ['rggb', 'bggr', 'grbg', 'gbrg']
DEFAULT_IMAGENAME_FORMAT = r'cam{r:d}_{c:d}.bmp'
[docs]
def resize_as_square(images, axes=(2, 3)):
"""Slice your image retaining the center square.
Parameters
----------
images: array-like
numpy-like array containing the following leading dimensions
`['image_y', 'image_x', 'y', 'x']`.
Returns
-------
images: array-like
With equal dimensions on the 'y' and 'x' dimensions.
"""
x_axis = axes[1]
y_axis = axes[0]
shape = images.shape
if shape[x_axis] == shape[y_axis]:
return images
else:
to_cut = shape[x_axis] - shape[y_axis]
if to_cut > 0:
index = x_axis
else:
index = y_axis
if index < 0:
index = len(shape) + index
to_cut = abs(to_cut)
to_cut_start = to_cut // 2
if to_cut_start > 0 or to_cut % 2 != 0:
the_slice = slice(to_cut_start, -(to_cut_start + to_cut % 2))
images = images[(slice(None,),) * index + (the_slice,)]
return images
[docs]
def trim_to_valid(dataset):
"""Trim the dataset to the valid data.
If ``valid_data`` is contained within the dataset, then the dataset is
sliced such that the removed data contains only invalid data.
Basic slicing is supported, such as contiguous slices, or slices with
steps. The slicing is done using the ``image_y`` and ``image_x`` dimensions
of the dataset.
"""
if 'valid_data' not in dataset:
return dataset
valid_data = dataset.valid_data.compute()
valid = valid_data.any()
if not valid:
raise RuntimeError("Dataset does not contain any valid data.")
valid_image_y = np.asarray(
valid_data.any(set(valid_data.dims) - set(('image_y',)))
)
valid_image_x = np.asarray(
valid_data.any(set(valid_data.dims) - set(('image_x',)))
)
valid_y = list(valid_image_y)
valid_x = list(valid_image_x)
start_y = valid_y.index(True)
end_y = len(valid_y) - valid_y[::-1].index(True)
start_x = valid_x.index(True)
end_x = len(valid_x) - valid_x[::-1].index(True)
max_len_y = max(end_y - start_y, 1)
N_valid_y = np.sum(valid_image_y)
# We know for sure that the two ends must be included
# So we don't have to look for the starting index
for skip_y in reversed(range(max_len_y)[1:]):
if np.sum(valid_image_y[start_y:end_y:skip_y]) == N_valid_y:
break
else:
skip_y = 1
max_len_x = max(end_x - start_x, 1)
N_valid_x = np.sum(valid_image_x)
for skip_x in reversed(range(max_len_x)[1:]):
if np.sum(valid_image_x[start_x:end_x:skip_x]) == N_valid_x:
break
else:
skip_x = 1
the_slice_y = slice(start_y, end_y, skip_y)
the_slice_x = slice(start_x, end_x, skip_x)
return dataset.isel(image_y=the_slice_y, image_x=the_slice_x)
[docs]
def get_valid_data(dataset):
"""Get the valid data from the dataset.
If the dataset contains a variable named ``valid_data``, then the
variable is used to determine the valid data.
If not, then a boolean array of the same shape as the images is returned.
"""
if 'valid_data' in dataset:
valid_data = np.asarray(dataset.valid_data.any(
dim=[
d
for d in dataset.valid_data.dims
if d not in ('image_y', 'image_x')
]
))
else:
valid_data = np.ones(
(dataset.sizes["image_y"], dataset.sizes["image_x"]), dtype=bool
)
return valid_data
def remove_invalid_images(dataset, axis=('image_y', 'image_x')):
"""Remove indices along the give axis that are completely invalid.
Parameters
----------
dataset : xarray.Dataset
The dataset to be trimmed.
Returns
-------
xarray.Dataset
The trimmed dataset.
"""
if isinstance(axis, str):
axis = (axis,)
if 'valid_data' not in dataset:
return dataset
isel_dict = {}
for ax in axis:
if ax not in dataset.dims:
raise ValueError(f"axis {ax} not in dataset images dims {dataset.dims}")
index_array = np.asarray(dataset.valid_data.any(
dim=[
d
for d in dataset.valid_data.dims
if d != ax
]
))
isel_dict[ax] = index_array
# We rely on outer indexing provided by xarray
# See the discussion on how this is not the "basic" indexing
# provided by numpy arrays
# https://mail.python.org/archives/list/numpy-discussion@python.org/thread/M43RXEN3R7XRZ7ARUWNX6SL4JMH6GZ7R/
# Howevever, some of our datasets are naturally sparse along certain outer dimensions
# the cost of calling dataset.isel twice is low enough that we can call it this way.
for key, value in isel_dict.items():
dataset = dataset.isel({key: value})
return dataset
def get_valid_metadata(dataset, metadata_key):
if 'valid_data' not in dataset:
# Return the full array, flattened, as it would be if we indexed
# it with an array of all boolean values
return dataset[metadata_key].data.flatten()
# The valid data may not be of the same dimensions of the array
# Case #1:
# The data_array may come in with some of the image_y or image_x
# as constants or dimensions independent of the valid_data
# To get through this, we must collapse the valid data first,
# Then use that to index the data_array
# Case #2:
# The data_array may have more dimensions than the
variable = dataset[metadata_key]
valid_data = dataset.valid_data.broadcast_like(variable)
valid_data = valid_data.any(
dim=[
d
for d in valid_data.dims
if d not in variable.dims
]
)
valid_data = np.asarray(valid_data)
return variable.data[valid_data]
def populate_fake_device_dataset(mcam):
from ._new import new_dataset
from .samples import (
hoechst_gfp_96wellplate,
larval_zebrafish_screening_IR,
sw620_spheroids,
zebrafish_in_a_96wellplate,
zebrafish_in_a_96wellplate_inverted_kestrel,
zebrafish_screening_morphology_square_wells,
)
# By default, the acquisition mode is "noise" but that
# causes the GUI to be ugly on the first acquisition.
# Since we need to be able to use this for screenshots
# I don't want the screenshots to look terrible on the first go
# This behavior may change in the future.
# mcam._falcon._fake_acquisition_settings['acquisition_mode'] = 'increment'
mcam._falcon._fake_acquisition_settings['acquisition_mode'] = 'noise'
# Big giant hack to get the fake MCAM to look decent in test scenarios
if mcam._falcon.dna_string == "0x4EADBEEFCAFE1010BA5EBA11":
# This sample dataset is quite specific to this particular Fake MCAM
dataset = zebrafish_in_a_96wellplate()
elif mcam._falcon.dna_string == "0x4EADBEEFCAFE1010BA5EDA11":
dataset = zebrafish_in_a_96wellplate_inverted_kestrel()
elif mcam.serial_number in ["Kestrel0010R"]:
dataset = zebrafish_screening_morphology_square_wells()
elif mcam.serial_number in ["Kestrel0053R"]:
dataset = larval_zebrafish_screening_IR()
elif mcam.serial_number in [
"Vireo1101R",
"Vireo1107R",
"Vireo1109R",
"Vireo1111R",
# Vireo1108 setup is automation only hardware.
"Vireo1108",
"Vireo1108R",
]:
dataset = sw620_spheroids()
elif mcam.serial_number in ["Vireo1112R"]:
dataset = hoechst_gfp_96wellplate()
elif mcam.serial_number == "Falcon0106R":
dataset = new_dataset(
N_cameras=mcam.N_cameras,
image_shape=(3136, 4224),
)
dataset.images.data[...] = 20
dataset.images.data[0:5, 0:5][..., 1::2, 0::2] = 128
dataset.images.data[4:9, 1:6][..., 0::2, 1::2] = 128
else:
return
mcam._falcon._fake_acquisition_settings['dataset'] = dataset