Skip to content
Snippets Groups Projects
Commit c78d0427 authored by Alán Muñoz's avatar Alán Muñoz
Browse files

change(aliby): move omero Image to omero.py

parent 1c668ecc
No related branches found
No related tags found
No related merge requests found
......@@ -6,29 +6,11 @@ from datetime import datetime
from pathlib import Path, PosixPath
import dask.array as da
import numpy as np
import xmltodict
from dask import delayed
from dask.array.image import imread
from omero.model import enums as omero_enums
from tifffile import TiffFile
from yaml import safe_load
from agora.io.bridge import BridgeH5
from agora.io.metadata import dir_to_meta
from aliby.io.omero import BridgeOmero
# convert OMERO definitions into numpy types
PIXEL_TYPES = {
omero_enums.PixelsTypeint8: np.int8,
omero_enums.PixelsTypeuint8: np.uint8,
omero_enums.PixelsTypeint16: np.int16,
omero_enums.PixelsTypeuint16: np.uint16,
omero_enums.PixelsTypeint32: np.int32,
omero_enums.PixelsTypeuint32: np.uint32,
omero_enums.PixelsTypefloat: np.float32,
omero_enums.PixelsTypedouble: np.float64,
}
def get_image_class(source: t.Union[str, int, t.Dict[str, str], PosixPath]):
......@@ -36,6 +18,8 @@ def get_image_class(source: t.Union[str, int, t.Dict[str, str], PosixPath]):
Wrapper to pick the appropiate Image class depending on the source of data.
"""
if isinstance(source, int):
from aliby.io.omero import Image
instatiator = Image
elif isinstance(source, dict) or (
isinstance(source, (str, PosixPath)) and Path(source).is_dir()
......@@ -262,138 +246,3 @@ class ImageDir(BaseLocalImage):
return [
k.split("_")[-1] for k in self._meta.keys() if k.startswith("size")
]
class Image(BridgeOmero):
"""
Loads images from OMERO and gives access to the data and metadata.
"""
def __init__(self, image_id: int, **server_info):
"""
Establishes the connection to the OMERO server via the Argo
base class.
Parameters
----------
image_id: integer
server_info: dictionary
Specifies the host, username, and password as strings
"""
self.ome_id = image_id
super().__init__(**server_info)
def init_interface(self, ome_id: int):
self.set_id(ome_id)
self.ome_class = self.conn.getObject("Image", ome_id)
@classmethod
def from_h5(
cls,
filepath: t.Union[str, PosixPath],
):
"""Instatiate Image from a hdf5 file.
Parameters
----------
cls : Image
Image class
filepath : t.Union[str, PosixPath]
Location of hdf5 file.
Examples
--------
FIXME: Add docs.
"""
# metadata = load_attributes(filepath)
bridge = BridgeH5(filepath)
image_id = bridge.meta_h5["image_id"]
# server_info = safe_load(bridge.meta_h5["parameters"])["general"][
# "server_info"
# ]
return cls(image_id, **cls.server_info_from_h5(filepath))
@property
def name(self):
return self.ome_class.getName()
@property
def data(self):
return get_data_lazy(self.ome_class)
@property
def metadata(self):
"""
Store metadata saved in OMERO: image size, number of time points,
labels of channels, and image name.
"""
meta = dict()
meta["size_x"] = self.ome_class.getSizeX()
meta["size_y"] = self.ome_class.getSizeY()
meta["size_z"] = self.ome_class.getSizeZ()
meta["size_c"] = self.ome_class.getSizeC()
meta["size_t"] = self.ome_class.getSizeT()
meta["channels"] = self.ome_class.getChannelLabels()
meta["name"] = self.ome_class.getName()
return meta
class UnsafeImage(Image):
"""
Loads images from OMERO and gives access to the data and metadata.
This class is a temporary solution while we find a way to use
context managers inside napari. It risks resulting in zombie connections
and producing freezes in an OMERO server.
"""
def __init__(self, image_id, **server_info):
"""
Establishes the connection to the OMERO server via the Argo
base class.
Parameters
----------
image_id: integer
server_info: dictionary
Specifies the host, username, and password as strings
"""
super().__init__(image_id, **server_info)
self.create_gate()
self.init_wrapper()
@property
def data(self):
try:
return get_data_lazy(self.ome_class)
except Exception as e:
print(f"ERROR: Failed fetching image from server: {e}")
self.conn.connect(False)
def get_data_lazy(image) -> da.Array:
"""
Get 5D dask array, with delayed reading from OMERO image.
"""
nt, nc, nz, ny, nx = [getattr(image, f"getSize{x}")() for x in "TCZYX"]
pixels = image.getPrimaryPixels()
dtype = PIXEL_TYPES.get(pixels.getPixelsType().value, None)
# using dask
get_plane = delayed(lambda idx: pixels.getPlane(*idx))
def get_lazy_plane(zct):
return da.from_delayed(get_plane(zct), shape=(ny, nx), dtype=dtype)
# 5D stack: TCZXY
t_stacks = []
for t in range(nt):
c_stacks = []
for c in range(nc):
z_stack = []
for z in range(nz):
z_stack.append(get_lazy_plane((z, c, t)))
c_stacks.append(da.stack(z_stack))
t_stacks.append(da.stack(c_stacks))
return da.stack(t_stacks)
"""
Tools to manage I/O using a remote OMERO server.
"""
import re
import typing as t
from abc import abstractmethod
from pathlib import PosixPath
import dask.array as da
import numpy as np
import omero
from dask import delayed
from omero.gateway import BlitzGateway
from omero.model import enums as omero_enums
from yaml import safe_load
from agora.io.bridge import BridgeH5
from aliby.io.omero import BridgeOmero
# convert OMERO definitions into numpy types
PIXEL_TYPES = {
omero_enums.PixelsTypeint8: np.int8,
omero_enums.PixelsTypeuint8: np.uint8,
omero_enums.PixelsTypeint16: np.int16,
omero_enums.PixelsTypeuint16: np.uint16,
omero_enums.PixelsTypeint32: np.int32,
omero_enums.PixelsTypeuint32: np.uint32,
omero_enums.PixelsTypefloat: np.float32,
omero_enums.PixelsTypedouble: np.float64,
}
class BridgeOmero:
......@@ -195,7 +216,7 @@ class Dataset(BridgeOmero):
def cache_logs(self, root_dir):
valid_suffixes = ("txt", "log")
for name, annotation in self.files.items():
for _, annotation in self.files.items():
filepath = root_dir / annotation.getFileName().replace("/", "_")
if (
any([str(filepath).endswith(suff) for suff in valid_suffixes])
......@@ -234,3 +255,138 @@ class Dataset(BridgeOmero):
return cls(
bridge.meta_h5[k], **cls.server_info_from_h5(filepath)
)
class Image(BridgeOmero):
"""
Loads images from OMERO and gives access to the data and metadata.
"""
def __init__(self, image_id: int, **server_info):
"""
Establishes the connection to the OMERO server via the Argo
base class.
Parameters
----------
image_id: integer
server_info: dictionary
Specifies the host, username, and password as strings
"""
self.ome_id = image_id
super().__init__(**server_info)
def init_interface(self, ome_id: int):
self.set_id(ome_id)
self.ome_class = self.conn.getObject("Image", ome_id)
@classmethod
def from_h5(
cls,
filepath: t.Union[str, PosixPath],
):
"""Instatiate Image from a hdf5 file.
Parameters
----------
cls : Image
Image class
filepath : t.Union[str, PosixPath]
Location of hdf5 file.
Examples
--------
FIXME: Add docs.
"""
# metadata = load_attributes(filepath)
bridge = BridgeH5(filepath)
image_id = bridge.meta_h5["image_id"]
# server_info = safe_load(bridge.meta_h5["parameters"])["general"][
# "server_info"
# ]
return cls(image_id, **cls.server_info_from_h5(filepath))
@property
def name(self):
return self.ome_class.getName()
@property
def data(self):
return get_data_lazy(self.ome_class)
@property
def metadata(self):
"""
Store metadata saved in OMERO: image size, number of time points,
labels of channels, and image name.
"""
meta = dict()
meta["size_x"] = self.ome_class.getSizeX()
meta["size_y"] = self.ome_class.getSizeY()
meta["size_z"] = self.ome_class.getSizeZ()
meta["size_c"] = self.ome_class.getSizeC()
meta["size_t"] = self.ome_class.getSizeT()
meta["channels"] = self.ome_class.getChannelLabels()
meta["name"] = self.ome_class.getName()
return meta
class UnsafeImage(Image):
"""
Loads images from OMERO and gives access to the data and metadata.
This class is a temporary solution while we find a way to use
context managers inside napari. It risks resulting in zombie connections
and producing freezes in an OMERO server.
"""
def __init__(self, image_id, **server_info):
"""
Establishes the connection to the OMERO server via the Argo
base class.
Parameters
----------
image_id: integer
server_info: dictionary
Specifies the host, username, and password as strings
"""
super().__init__(image_id, **server_info)
self.create_gate()
self.init_wrapper()
@property
def data(self):
try:
return get_data_lazy(self.ome_class)
except Exception as e:
print(f"ERROR: Failed fetching image from server: {e}")
self.conn.connect(False)
def get_data_lazy(image) -> da.Array:
"""
Get 5D dask array, with delayed reading from OMERO image.
"""
nt, nc, nz, ny, nx = [getattr(image, f"getSize{x}")() for x in "TCZYX"]
pixels = image.getPrimaryPixels()
dtype = PIXEL_TYPES.get(pixels.getPixelsType().value, None)
# using dask
get_plane = delayed(lambda idx: pixels.getPlane(*idx))
def get_lazy_plane(zct):
return da.from_delayed(get_plane(zct), shape=(ny, nx), dtype=dtype)
# 5D stack: TCZXY
t_stacks = []
for t in range(nt):
c_stacks = []
for c in range(nc):
z_stack = []
for z in range(nz):
z_stack.append(get_lazy_plane((z, c, t)))
c_stacks.append(da.stack(z_stack))
t_stacks.append(da.stack(c_stacks))
return da.stack(t_stacks)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment