From 60ab61ad525671370b730625372480daf33339d0 Mon Sep 17 00:00:00 2001 From: William Moore Date: Thu, 16 Sep 2021 12:06:07 +0100 Subject: [PATCH 1/5] Use nested chunk store for labels --- src/omero_zarr/masks.py | 7 ++++--- src/omero_zarr/raw_pixels.py | 20 +++----------------- src/omero_zarr/util.py | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/omero_zarr/masks.py b/src/omero_zarr/masks.py index 0fe0fb8..1dd6a72 100644 --- a/src/omero_zarr/masks.py +++ b/src/omero_zarr/masks.py @@ -16,9 +16,9 @@ from omero.model import MaskI, PolygonI from omero.rtypes import unwrap from skimage.draw import polygon as sk_polygon -from zarr.convenience import open as zarr_open +from zarr.hierarchy import open_group -from .util import print_status +from .util import open_store, print_status # Mapping of dimension names to axes in the Zarr DIMENSION_ORDER: Dict[str, int] = { @@ -278,7 +278,8 @@ def save(self, masks: List[omero.model.Shape], name: str) -> None: assert input_pyramid.load(Multiscales), "No multiscales metadata found" input_pyramid_levels = len(input_pyramid.data) - root = zarr_open(filename) + store = open_store(filename) + root = open_group(store) if current_path in root.group_keys(): out_labels = getattr(root, current_path) diff --git a/src/omero_zarr/raw_pixels.py b/src/omero_zarr/raw_pixels.py index ba7df64..43de8d4 100644 --- a/src/omero_zarr/raw_pixels.py +++ b/src/omero_zarr/raw_pixels.py @@ -10,24 +10,10 @@ from omero.rtypes import unwrap from skimage.transform import resize from zarr.hierarchy import Array, Group, open_group -from zarr.storage import FSStore from . import __version__ from . import ngff_version as VERSION -from .util import print_status - - -def _open_store(name: str) -> FSStore: - """ - Create an FSStore instance that supports nested storage of chunks. - """ - return FSStore( - name, - auto_mkdir=True, - key_separator="/", - normalize_keys=False, - mode="w", - ) +from .util import open_store, print_status def image_to_zarr(image: omero.gateway.ImageWrapper, args: argparse.Namespace) -> None: @@ -36,7 +22,7 @@ def image_to_zarr(image: omero.gateway.ImageWrapper, args: argparse.Namespace) - name = os.path.join(target_dir, "%s.zarr" % image.id) print(f"Exporting to {name} ({VERSION})") - store = _open_store(name) + store = open_store(name) root = open_group(store) n_levels, axes = add_image(image, root, cache_dir=cache_dir) add_multiscales_metadata(root, axes, n_levels) @@ -226,7 +212,7 @@ def plate_to_zarr(plate: omero.gateway._PlateWrapper, args: argparse.Namespace) target_dir = args.output cache_dir = target_dir if args.cache_numpy else None name = os.path.join(target_dir, "%s.zarr" % plate.id) - store = _open_store(name) + store = open_store(name) print(f"Exporting to {name} ({VERSION})") root = open_group(store) diff --git a/src/omero_zarr/util.py b/src/omero_zarr/util.py index 3262b47..7148ead 100644 --- a/src/omero_zarr/util.py +++ b/src/omero_zarr/util.py @@ -1,5 +1,7 @@ import time +from zarr.storage import FSStore + def print_status(t0: int, t: int, count: int, total: int) -> None: """Prints percent done and ETA. @@ -18,3 +20,16 @@ def print_status(t0: int, t: int, count: int, total: int) -> None: eta = "NA" status = f"{percent_done:.2f}% done, ETA: {eta}" print(status, end="\r", flush=True) + + +def open_store(name: str) -> FSStore: + """ + Create an FSStore instance that supports nested storage of chunks. + """ + return FSStore( + name, + auto_mkdir=True, + key_separator="/", + normalize_keys=False, + mode="w", + ) From 52bd467d2fa815b3f26dd3c4e32f3d64e02d2a7b Mon Sep 17 00:00:00 2001 From: William Moore Date: Thu, 16 Sep 2021 14:49:25 +0100 Subject: [PATCH 2/5] Use version 0.3 in labels --- src/omero_zarr/masks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/omero_zarr/masks.py b/src/omero_zarr/masks.py index 1dd6a72..cfec398 100644 --- a/src/omero_zarr/masks.py +++ b/src/omero_zarr/masks.py @@ -313,7 +313,7 @@ def save(self, masks: List[omero.model.Shape], name: str) -> None: image_label_colors: List[JSONDict] = [] label_properties: List[JSONDict] = [] image_label = { - "version": "0.2", + "version": "0.3", "colors": image_label_colors, "properties": label_properties, "source": {"image": source_image_link}, From 56d8b17c62396b08c43883aeb3cc0695f48613f7 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 27 Sep 2021 17:06:52 +0100 Subject: [PATCH 3/5] squeeze dimensions of labels to match image --- src/omero_zarr/masks.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/omero_zarr/masks.py b/src/omero_zarr/masks.py index cfec398..f9a97e6 100644 --- a/src/omero_zarr/masks.py +++ b/src/omero_zarr/masks.py @@ -303,11 +303,24 @@ def save(self, masks: List[omero.model.Shape], name: str) -> None: ignored_dimensions, check_overlaps=True, ) + # For v0.3 ngff we want to reduce the number of dimensions to + # match the dims of the Image. + dims_to_squeeze = [] + axes = [] + for dim, size in enumerate(self.image_shape): + if size == 1 or dim == 1: # always squeeze channel (dim=1) + dims_to_squeeze.append(dim) + else: + axes.append("tczyx"[dim]) + labels = np.squeeze(labels, axis=tuple(dims_to_squeeze)) + scaler = Scaler(max_layer=input_pyramid_levels) label_pyramid = scaler.nearest(labels) pyramid_grp = out_labels.require_group(name) - write_multiscale(label_pyramid, pyramid_grp) # TODO: dtype, chunks, overwite + write_multiscale( + label_pyramid, pyramid_grp, axes=axes + ) # TODO: dtype, chunks, overwite # Specify and store metadata image_label_colors: List[JSONDict] = [] From 3dc087c2c0fa4120c7a05c6c8ce1352fa36edaed Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 27 Sep 2021 17:38:58 +0100 Subject: [PATCH 4/5] Don't squeeze channel dimension size_C may not be 1 if the masks have C index set --- src/omero_zarr/masks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/omero_zarr/masks.py b/src/omero_zarr/masks.py index f9a97e6..921b860 100644 --- a/src/omero_zarr/masks.py +++ b/src/omero_zarr/masks.py @@ -308,7 +308,7 @@ def save(self, masks: List[omero.model.Shape], name: str) -> None: dims_to_squeeze = [] axes = [] for dim, size in enumerate(self.image_shape): - if size == 1 or dim == 1: # always squeeze channel (dim=1) + if size == 1: dims_to_squeeze.append(dim) else: axes.append("tczyx"[dim]) From 896cdd80e5ef35db2ce2a4d7ba653c85dcf224ac Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 12 Oct 2021 13:07:43 +0100 Subject: [PATCH 5/5] setup.py requires ome-zarr>=0.2.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d0e2b3e..e0bacce 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ def get_long_description() -> str: author="The Open Microscopy Team", author_email="", python_requires=">=3", - install_requires=["omero-py>=5.6.0", "ome-zarr"], + install_requires=["omero-py>=5.6.0", "ome-zarr>=0.2.0"], long_description=long_description, keywords=["OMERO.CLI", "plugin"], url="https://github.com/ome/omero-cli-zarr/",