Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • swain-lab/aliby/aliby-mirror
  • swain-lab/aliby/alibylite
2 results
Show changes
Showing
with 1691 additions and 2125 deletions
"""
Neural network initialisation.
"""
from pathlib import Path
from time import perf_counter
import numpy as np
import tensorflow as tf
from agora.io.writer import DynamicWriter
def initialise_tf(version):
# Initialise tensorflow
if version == 1:
core_config = tf.ConfigProto()
core_config.gpu_options.allow_growth = True
session = tf.Session(config=core_config)
return session
# TODO this only works for TF2
if version == 2:
gpus = tf.config.experimental.list_physical_devices("GPU")
if gpus:
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
logical_gpus = tf.config.experimental.list_logical_devices("GPU")
print(
len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPUs"
)
return None
def timer(func, *args, **kwargs):
start = perf_counter()
result = func(*args, **kwargs)
print(f"Function {func.__name__}: {perf_counter() - start}s")
return result
################## CUSTOM OBJECTS ##################################
class ModelPredictor:
"""Generic object that takes a NN and returns the prediction.
Use for predicting fluorescence/other from bright field.
This does not do instance segmentations of anything.
"""
def __init__(self, tiler, model, name):
self.tiler = tiler
self.model = model
self.name = name
def get_data(self, tp):
# Change axes to X,Y,Z rather than Z,Y,X
return (
self.tiler.get_tp_data(tp, self.bf_channel)
.swapaxes(1, 3)
.swapaxes(1, 2)
)
def format_result(self, result, tp):
return {self.name: result, "timepoints": [tp] * len(result)}
def run_tp(self, tp):
"""Simulating processing time with sleep"""
# Access the image
segmentation = self.model.predict(self.get_data(tp))
return self._format_result(segmentation, tp)
class ModelPredictorWriter(DynamicWriter):
def __init__(self, file, name, shape, dtype):
super.__init__(file)
self.datatypes = {
name: (shape, dtype),
"timepoint": ((None,), np.uint16),
}
self.group = f"{self.name}_info"
......@@ -54,7 +54,7 @@ class DatasetLocalABC(ABC):
Abstract Base class to find local files, either OME-XML or raw images.
"""
_valid_suffixes = ("tiff", "png", "zarr")
_valid_suffixes = ("tiff", "png", "zarr", "tif")
_valid_meta_suffixes = ("txt", "log")
def __init__(self, dpath: t.Union[str, Path], *args, **kwargs):
......
......@@ -29,15 +29,11 @@ from tifffile import TiffFile
from agora.io.metadata import dir_to_meta, dispatch_metadata_parser
def get_examples_dir():
"""Get examples directory which stores dummy image for tiler"""
return files("aliby").parent.parent / "examples" / "tiler"
def instantiate_image(
source: t.Union[str, int, t.Dict[str, str], Path], **kwargs
):
"""Wrapper to instatiate the appropiate image
"""
Instantiate the image.
Parameters
----------
......@@ -46,42 +42,38 @@ def instantiate_image(
Examples
--------
image_path = "path/to/image"]
image_path = "path/to/image"
with instantiate_image(image_path) as img:
print(imz.data, img.metadata)
"""
return dispatch_image(source)(source, **kwargs)
def dispatch_image(source: t.Union[str, int, t.Dict[str, str], Path]):
"""
Wrapper to pick the appropiate Image class depending on the source of data.
"""
"""Pick the appropriate Image class depending on the source of data."""
if isinstance(source, (int, np.int64)):
from aliby.io.omero import Image
instatiator = Image
instantiator = Image
elif isinstance(source, dict) or (
isinstance(source, (str, Path)) and Path(source).is_dir()
):
# zarr files are considered directories
if Path(source).suffix == ".zarr":
instatiator = ImageZarr
instantiator = ImageZarr
else:
instatiator = ImageDir
elif isinstance(source, str) and Path(source).is_file():
instatiator = ImageLocalOME
instantiator = ImageDir
elif isinstance(source, (str, Path)) and Path(source).is_file():
instantiator = ImageLocalOME
else:
raise Exception(f"Invalid data source at {source}")
return instatiator
return instantiator
class BaseLocalImage(ABC):
"""
Base Image class to set path and provide context management method.
"""
"""Set path and provide method for context management."""
# default image order
_default_dimorder = "tczyx"
def __init__(self, path: t.Union[str, Path]):
......@@ -98,8 +90,7 @@ class BaseLocalImage(ABC):
return False
def rechunk_data(self, img):
# Format image using x and y size from metadata.
"""Format image using x and y size from metadata."""
self._rechunked_img = da.rechunk(
img,
chunks=(
......@@ -112,30 +103,35 @@ class BaseLocalImage(ABC):
)
return self._rechunked_img
@property
def data(self):
"""Get data."""
return self.get_data_lazy()
@property
def metadata(self):
"""Get metadata."""
return self._meta
def set_meta(self):
"""Load metadata using parser dispatch."""
self._meta = dispatch_metadata_parser(self.path)
@abstractmethod
def get_data_lazy(self) -> da.Array:
"""Define in child class."""
pass
@abstractproperty
def name(self):
"""Define in child class."""
pass
@abstractproperty
def dimorder(self):
"""Define in child class."""
pass
@property
def data(self):
return self.get_data_lazy()
@property
def metadata(self):
return self._meta
def set_meta(self):
"""Load metadata using parser dispatch"""
self._meta = dispatch_metadata_parser(self.path)
class ImageLocalOME(BaseLocalImage):
"""
......@@ -145,16 +141,18 @@ class ImageLocalOME(BaseLocalImage):
in which a multidimensional tiff image contains the metadata.
"""
def __init__(self, path: str, dimorder=None):
def __init__(self, path: str, dimorder=None, **kwargs):
"""Initialise using file name."""
super().__init__(path)
self._id = str(path)
self.set_meta(str(path))
def set_meta(self):
def set_meta(self, path):
"""Get metadata from the associated tiff file."""
meta = dict()
try:
with TiffFile(path) as f:
self._meta = xmltodict.parse(f.ome_metadata)["OME"]
for dim in self.dimorder:
meta["size_" + dim.lower()] = int(
self._meta["Image"]["Pixels"]["@Size" + dim]
......@@ -165,21 +163,19 @@ class ImageLocalOME(BaseLocalImage):
]
meta["name"] = self._meta["Image"]["@Name"]
meta["type"] = self._meta["Image"]["Pixels"]["@Type"]
except Exception as e: # Images not in OMEXML
except Exception as e:
# images not in OMEXML
print("Warning:Metadata not found: {}".format(e))
print(
f"Warning: No dimensional info provided. Assuming {self._default_dimorder}"
"Warning: No dimensional info provided. "
f"Assuming {self._default_dimorder}"
)
# Mark non-existent dimensions for padding
# mark non-existent dimensions for padding
self.base = self._default_dimorder
# self.ids = [self.index(i) for i in dimorder]
self._dimorder = base
self._dimorder = self.base
self._meta = meta
# self._meta["name"] = Path(path).name.split(".")[0]
@property
def name(self):
......@@ -196,7 +192,7 @@ class ImageLocalOME(BaseLocalImage):
@property
def dimorder(self):
"""Order of dimensions in image"""
"""Return order of dimensions in the image."""
if not hasattr(self, "_dimorder"):
self._dimorder = self._meta["Image"]["Pixels"]["@DimensionOrder"]
return self._dimorder
......@@ -207,16 +203,16 @@ class ImageLocalOME(BaseLocalImage):
return self._dimorder
def get_data_lazy(self) -> da.Array:
"""Return 5D dask array. For lazy-loading multidimensional tiff files"""
"""Return 5D dask array via lazy-loading of tiff files."""
if not hasattr(self, "formatted_img"):
if not hasattr(self, "ids"): # Standard dimension order
if not hasattr(self, "ids"):
# standard order of image dimensions
img = (imread(str(self.path))[0],)
else: # Custom dimension order, we rearrange the axes for compatibility
else:
# bespoke order, so rearrange axes for compatibility
img = imread(str(self.path))[0]
for i, d in enumerate(self._dimorder):
self._meta["size_" + d.lower()] = img.shape[i]
target_order = (
*self.ids,
*[
......@@ -235,42 +231,38 @@ class ImageLocalOME(BaseLocalImage):
img = da.moveaxis(
reshaped, range(len(reshaped.shape)), target_order
)
return self.rechunk_data(img)
class ImageDir(BaseLocalImage):
"""
Standard image class for tiff files.
Image class for the case in which all images are split in one or
multiple folders with time-points and channels as independent files.
It inherits from BaseLocalImage so we only override methods that are critical.
Assumptions:
- One folders per position.
- One folder per position.
- Images are flat.
- Channel, Time, z-stack and the others are determined by filenames.
- Provides Dimorder as it is set in the filenames, or expects order during instatiation
- Provides Dimorder as it is set in the filenames, or expects order
"""
def __init__(self, path: t.Union[str, Path], **kwargs):
"""Initialise using file name."""
super().__init__(path)
self.image_id = str(self.path.stem)
self._meta = dir_to_meta(self.path)
def get_data_lazy(self) -> da.Array:
"""Return 5D dask array. For lazy-loading local multidimensional tiff files"""
"""Return 5D dask array."""
img = imread(str(self.path / "*.tiff"))
# If extra channels, pick the first stack of the last dimensions
while len(img.shape) > 3:
img = img[..., 0]
if self._meta:
self._meta["size_x"], self._meta["size_y"] = img.shape[-2:]
# Reshape using metadata
# img = da.reshape(img, (*self._meta, *img.shape[1:]))
img = da.reshape(img, self._meta.values())
......@@ -291,6 +283,7 @@ class ImageDir(BaseLocalImage):
@property
def name(self):
"""Return name of image directory."""
return self.path.stem
@property
......@@ -304,24 +297,27 @@ class ImageDir(BaseLocalImage):
class ImageZarr(BaseLocalImage):
"""
Read zarr compressed files.
These are outputed by the script
These files are generated by the script
skeletons/scripts/howto_omero/convert_clone_zarr_to_tiff.py
"""
def __init__(self, path: t.Union[str, Path], **kwargs):
"""Initialise using file name."""
super().__init__(path)
self.set_meta()
try:
self._img = zarr.open(self.path)
self.add_size_to_meta()
except Exception as e:
print(f"Could not add size info to metadata: {e}")
print(f"ImageZarr: Could not add size info to metadata: {e}.")
def get_data_lazy(self) -> da.Array:
"""Return 5D dask array. For lazy-loading local multidimensional zarr files"""
"""Return 5D dask array for lazy-loading local multidimensional zarr files."""
return self._img
def add_size_to_meta(self):
"""Add shape of image array to metadata."""
self._meta.update(
{
f"size_{dim}": shape
......@@ -331,16 +327,13 @@ class ImageZarr(BaseLocalImage):
@property
def name(self):
"""Return name of zarr directory."""
return self.path.stem
@property
def dimorder(self):
# FIXME hardcoded order based on zarr compression/cloning script
"""Impose a hard-coded order of dimensions based on the zarr compression script."""
return "TCZYX"
# Assumes only dimensions start with "size"
# return [
# k.split("_")[-1] for k in self._meta.keys() if k.startswith("size")
# ]
class ImageDummy(BaseLocalImage):
......
......@@ -131,7 +131,6 @@ class BridgeOmero:
FIXME: Add docs.
"""
# metadata = load_attributes(filepath)
bridge = BridgeH5(filepath)
meta = safe_load(bridge.meta_h5["parameters"])["general"]
server_info = {k: meta[k] for k in ("host", "username", "password")}
......@@ -208,6 +207,13 @@ class Dataset(BridgeOmero):
im.getName(): im.getId() for im in self.ome_class.listChildren()
}
def get_channels(self):
"""Get channels from OMERO."""
for im in self.ome_class.listChildren():
channels = [ch.getLabel() for ch in im.getChannels()]
break
return channels
@property
def files(self):
if not hasattr(self, "_files"):
......@@ -254,7 +260,8 @@ class Dataset(BridgeOmero):
cls,
filepath: t.Union[str, Path],
):
"""Instatiate Dataset from a hdf5 file.
"""
Instantiate data set from a h5 file.
Parameters
----------
......@@ -268,7 +275,6 @@ class Dataset(BridgeOmero):
FIXME: Add docs.
"""
# metadata = load_attributes(filepath)
bridge = BridgeH5(filepath)
dataset_keys = ("omero_id", "omero_id,", "dataset_id")
for k in dataset_keys:
......@@ -301,21 +307,21 @@ class Image(BridgeOmero):
cls,
filepath: t.Union[str, Path],
):
"""Instatiate Image from a hdf5 file.
"""
Instantiate Image from a h5 file.
Parameters
----------
cls : Image
Image class
filepath : t.Union[str, Path]
Location of hdf5 file.
Location of h5 file.
Examples
--------
FIXME: Add docs.
"""
# metadata = load_attributes(filepath)
bridge = BridgeH5(filepath)
image_id = bridge.meta_h5["image_id"]
return cls(image_id, **cls.server_info_from_h5(filepath))
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -52,7 +52,7 @@ def plot_in_square(data: t.Iterable):
def stretch_clip(image, clip=True):
"""
Performs contrast stretching on an input image.
Perform contrast stretching on an input image.
This function takes an array-like input image and enhances its contrast by adjusting
the dynamic range of pixel values. It first scales the pixel values between 0 and 255,
......
__version__ = "0.1.64 lite"
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.