From 9a1229b439d003f40270728def989fb34e3dd1fb Mon Sep 17 00:00:00 2001 From: Joost de Folter Date: Fri, 26 Jan 2024 15:43:36 +0100 Subject: [PATCH] Added Dask converter for ome.tiff reader, other small improvements --- CHANGELOG.md | 3 +++ OmeSliCC/OmeSource.py | 14 +++++++++----- OmeSliCC/OmeZarrSource.py | 3 +++ OmeSliCC/TiffSource.py | 9 +++++++-- OmeSliCC/ome_zarr_util.py | 2 +- environment.yml | 1 + environment_no_bioformats.yml | 1 + pyproject.toml | 2 +- 8 files changed, 26 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6606035..27115c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +#### Version 0.6.2 +- Added Dask converter for ome.tiff reader + #### Version 0.6.1 - Rewritten code base supporting full multi-dimensional images - Improved (ome) zarr support diff --git a/OmeSliCC/OmeSource.py b/OmeSliCC/OmeSource.py index 253d545..fd18135 100644 --- a/OmeSliCC/OmeSource.py +++ b/OmeSliCC/OmeSource.py @@ -149,6 +149,9 @@ def _init_sizes(self): self.output_dimension_order = 'tczyx' + def as_dask(self): + raise NotImplementedError('Implement method in subclass') + def get_mag(self) -> float: mag = self.source_mag # get effective mag at target pixel size @@ -214,7 +217,7 @@ def get_thumbnail(self, target_size: tuple, precise: bool = False) -> np.ndarray thumbnail = self.render(image_resize(image, target_size)) return thumbnail - def get_window_min_max(self, channeli): + def get_channel_window(self, channeli): min_quantile = 0.001 max_quantile = 0.999 @@ -266,12 +269,13 @@ def render(self, image: np.ndarray, t: int = 0, z: int = 0, channels: list = []) else: channel_values = image[..., channeli] if do_normalisation: - window = self.get_window_min_max(channeli) + window = self.get_channel_window(channeli) channel_values = normalise_values(channel_values, window['min'], window['max']) else: channel_values = int2float_image(channel_values) - if 'color' in channel and channel['color'] != '': - rgba = channel['color'] + color = channel.get('color') + if color: + rgba = color else: rgba = [1, 1, 1, 1] color = rgba[:3] @@ -283,7 +287,7 @@ def render(self, image: np.ndarray, t: int = 0, z: int = 0, channels: list = []) tot_alpha += alpha new_image = float2int_image(new_image / tot_alpha) elif do_normalisation: - window = self.get_window_min_max(0) + window = self.get_channel_window(0) new_image = float2int_image(normalise_values(image, window['min'], window['max'])) else: new_image = image diff --git a/OmeSliCC/OmeZarrSource.py b/OmeSliCC/OmeZarrSource.py index be7dd90..d055f7a 100644 --- a/OmeSliCC/OmeZarrSource.py +++ b/OmeSliCC/OmeZarrSource.py @@ -98,6 +98,9 @@ def _find_metadata(self): self.channels = channels self.source_mag = 0 + def as_dask(self): + return self.levels + def _asarray_level(self, level: int, x0: float = 0, y0: float = 0, x1: float = -1, y1: float = -1, c: int = None, z: int = None, t: int = None) -> np.ndarray: if x1 < 0 or y1 < 0: diff --git a/OmeSliCC/TiffSource.py b/OmeSliCC/TiffSource.py index cd3cd27..a2b17b4 100644 --- a/OmeSliCC/TiffSource.py +++ b/OmeSliCC/TiffSource.py @@ -1,11 +1,12 @@ # https://pypi.org/project/tifffile/ -import os +from concurrent.futures import ThreadPoolExecutor +import dask.array as da from enum import Enum import numpy as np +import os from tifffile import TiffFile, TiffPage -from concurrent.futures import ThreadPoolExecutor from OmeSliCC import XmlDict from OmeSliCC.OmeSource import OmeSource @@ -51,6 +52,7 @@ def __init__(self, self.executor = ThreadPoolExecutor(max_workers) tiff = TiffFile(filename) + self.tiff = tiff self.first_page = tiff.pages.first if tiff.is_ome and tiff.ome_metadata is not None: xml_metadata = tiff.ome_metadata @@ -176,6 +178,9 @@ def _find_metadata(self): self.source_mag = mag self.channels = channels + def as_dask(self): + return [da.from_zarr(self.tiff.aszarr(level=level)) for level in range(len(self.sizes))] + def load(self, decompress: bool = False): self.fh.seek(0) self.data = self.fh.read() diff --git a/OmeSliCC/ome_zarr_util.py b/OmeSliCC/ome_zarr_util.py index a48e1c1..aa76c9f 100644 --- a/OmeSliCC/ome_zarr_util.py +++ b/OmeSliCC/ome_zarr_util.py @@ -44,7 +44,7 @@ def create_channel_metadata(source): if 'color' in channel: channel['color'] = rgba_to_hexrgb(channel['color']) if 'window' not in channel: - channel['window'] = source.get_window_min_max(channeli) + channel['window'] = source.get_channel_window(channeli) channels.append(channel) metadata = { diff --git a/environment.yml b/environment.yml index 628f60f..5fb39fd 100644 --- a/environment.yml +++ b/environment.yml @@ -14,6 +14,7 @@ dependencies: - scikit-learn - imagecodecs - numcodecs + - dask - tifffile - zarr - ome-zarr diff --git a/environment_no_bioformats.yml b/environment_no_bioformats.yml index 1f50155..83375f0 100644 --- a/environment_no_bioformats.yml +++ b/environment_no_bioformats.yml @@ -13,6 +13,7 @@ dependencies: - scikit-learn - imagecodecs - numcodecs + - dask - tifffile - zarr - ome-zarr diff --git a/pyproject.toml b/pyproject.toml index 222f92a..1b18157 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "OmeSliCC" -version = "0.6.1" +version = "0.6.2" description = "Ome(ro) Slide Image Conversion and Compression pipeline" readme = "README.md" license = {file = "LICENSE.md"}