From 87a8340e9b4de535314961081a518fc6887197d9 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 9 Jun 2025 17:14:40 +0100 Subject: [PATCH 1/4] Fix export of masks with multi-theC as multi-channel labels --- src/omero_zarr/masks.py | 6 +++-- test/integration/clitest/test_export.py | 32 ++++++++++++++----------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/omero_zarr/masks.py b/src/omero_zarr/masks.py index bf5ad0f..e9b3ef5 100644 --- a/src/omero_zarr/masks.py +++ b/src/omero_zarr/masks.py @@ -293,12 +293,14 @@ def save(self, masks: List[omero.model.Shape], name: str) -> None: # Figure out whether we can flatten some dimensions unique_dims: Dict[str, Set[int]] = { "T": {unwrap(mask.theT) for shapes in masks for mask in shapes}, + "C": {unwrap(mask.theC) for shapes in masks for mask in shapes}, "Z": {unwrap(mask.theZ) for shapes in masks for mask in shapes}, } ignored_dimensions: Set[str] = set() - # We always ignore the C dimension - ignored_dimensions.add("C") print(f"Unique dimensions: {unique_dims}") + # We always ignore the C dimension + if unique_dims["C"] == {None} or len(unique_dims["C"]) == 1: + ignored_dimensions.add("C") for d in "TZ": if unique_dims[d] == {None}: diff --git a/test/integration/clitest/test_export.py b/test/integration/clitest/test_export.py index d6145cc..d474c07 100644 --- a/test/integration/clitest/test_export.py +++ b/test/integration/clitest/test_export.py @@ -192,20 +192,21 @@ def test_export_masks( img_id = images[0].id.val size_xy = 512 - # Create a mask + # Create a mask for each channel from skimage.data import binary_blobs - blobs = binary_blobs(length=size_xy, volume_fraction=0.1, n_dim=2).astype( - "int8" - ) red = [255, 0, 0, 255] - mask = mask_from_binary_image(blobs, rgba=red, z=0, c=0, t=0) - - roi = RoiI() - roi.setImage(images[0]) - roi.addShape(mask) - updateService = self.client.sf.getUpdateService() - updateService.saveAndReturnObject(roi) + green = [0, 255, 0, 255] + for ch, color in enumerate([red, green]): + blobs = binary_blobs(length=size_xy, volume_fraction=0.1, n_dim=2).astype( + "int8" + ) + mask = mask_from_binary_image(blobs, rgba=color, z=0, c=ch, t=0) + roi = RoiI() + roi.setImage(images[0]) + roi.addShape(mask) + updateService = self.client.sf.getUpdateService() + updateService.saveAndReturnObject(roi) print("tmp_path", tmp_path) @@ -232,19 +233,22 @@ def test_export_masks( all_lines = ", ".join(lines) assert "Exporting to" in all_lines assert "Finished" in all_lines - assert "Found 1 mask shapes in 1 ROIs" in all_lines + assert "Found 2 mask shapes in 2 ROIs" in all_lines labels_text = (tmp_path / zarr_name / "labels" / "0" / ".zattrs").read_text( encoding="utf-8" ) labels_json = json.loads(labels_text) - assert labels_json["image-label"]["colors"] == [{"label-value": 1, "rgba": red}] + assert labels_json["image-label"]["colors"] == [ + {"label-value": 1, "rgba": red}, + {"label-value": 2, "rgba": green}, + ] arr_text = (tmp_path / zarr_name / "labels" / "0" / "0" / ".zarray").read_text( encoding="utf-8" ) arr_json = json.loads(arr_text) - assert arr_json["shape"] == [1, 512, 512] + assert arr_json["shape"] == [2, 512, 512] @pytest.mark.parametrize("name_by", ["id", "name"]) def test_export_plate_polygons( From a24a128d514126929476c541b2ec2853ec66e7d0 Mon Sep 17 00:00:00 2001 From: William Moore Date: Tue, 24 Jun 2025 12:56:14 +0100 Subject: [PATCH 2/4] Remove outdated comment --- src/omero_zarr/masks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/omero_zarr/masks.py b/src/omero_zarr/masks.py index e9b3ef5..c0af0c1 100644 --- a/src/omero_zarr/masks.py +++ b/src/omero_zarr/masks.py @@ -298,7 +298,6 @@ def save(self, masks: List[omero.model.Shape], name: str) -> None: } ignored_dimensions: Set[str] = set() print(f"Unique dimensions: {unique_dims}") - # We always ignore the C dimension if unique_dims["C"] == {None} or len(unique_dims["C"]) == 1: ignored_dimensions.add("C") From 1c0b1e6c44c4a14b122c64e9e422720b8ec85e52 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 18 Aug 2025 14:20:41 +0100 Subject: [PATCH 3/4] Fix years in CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b92b0e..ebb2cdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ -# 0.6.1 (June 2024) +# 0.6.1 (June 2025) - Fix version -# 0.6.0 (June 2024) +# 0.6.0 (June 2025) - Support --name_by option ([#147](https://github.com/ome/omero-cli-zarr/pull/147)) - Fix export of Plate labels ([#173](https://github.com/ome/omero-cli-zarr/pull/173)) From bb180dbb97ddc67cd2cf655d56058ba7da765769 Mon Sep 17 00:00:00 2001 From: William Moore Date: Mon, 18 Aug 2025 14:46:40 +0100 Subject: [PATCH 4/4] Cleanup print statements for labels export --- src/omero_zarr/masks.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/omero_zarr/masks.py b/src/omero_zarr/masks.py index d6caf75..cc97f43 100644 --- a/src/omero_zarr/masks.py +++ b/src/omero_zarr/masks.py @@ -309,8 +309,6 @@ def save(self, masks: List[omero.model.Shape], name: str) -> None: # Verify that we are linking this mask to a real ome-zarr source_image = self.source_image - print(f"source_image ??? needs to be None to use filename: {source_image}") - print(f"filename: {filename}", self.output, self.name_by) source_image_link = self.source_image if source_image is None: # Assume that we're using the output directory @@ -321,11 +319,11 @@ def save(self, masks: List[omero.model.Shape], name: str) -> None: assert self.plate_path, "Need image path within the plate" source_image = f"{source_image}/{self.plate_path}" - print(f"source_image {source_image}") image_path = source_image if self.output: image_path = os.path.join(self.output, source_image) src = parse_url(image_path) + print(f"Writing labels to image at: {image_path}") assert src, f"Source image does not exist at {image_path}" input_pyramid = Node(src, []) assert input_pyramid.load(Multiscales), "No multiscales metadata found" @@ -579,7 +577,7 @@ def masks_to_labels( if check_overlaps: raise Exception( f"Shape {shape.roi.id.val} overlaps " - "with existing labels" + "with existing labels. Use --overlaps=dtype_max" ) else: # set overlapping region to max(dtype)