From f3f3c8f0548278d8c296ba9bd9bafe01a2c770a1 Mon Sep 17 00:00:00 2001 From: Laurent Guerard Date: Wed, 25 Mar 2026 11:54:30 +0100 Subject: [PATCH 1/6] Add options to segment_3d_image for removing objects touching borders --- src/imcflibs/imagej/objects3d.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/imcflibs/imagej/objects3d.py b/src/imcflibs/imagej/objects3d.py index ce514c70..1476c8ae 100644 --- a/src/imcflibs/imagej/objects3d.py +++ b/src/imcflibs/imagej/objects3d.py @@ -71,7 +71,15 @@ def imgplus_to_population3d(imp): return Objects3DPopulation(img) -def segment_3d_image(imp, title=None, min_thresh=1, min_vol=None, max_vol=None): +def segment_3d_image( + imp, + title=None, + min_thresh=1, + min_vol=None, + max_vol=None, + remove_touching_borders=False, + remove_touching_borders_z=False, +): """Segment a 3D binary image to get a labelled stack. Parameters @@ -90,6 +98,11 @@ def segment_3d_image(imp, title=None, min_thresh=1, min_vol=None, max_vol=None): max_vol : int, optional Maximum volume (in voxels) above which objects get filtered. Defaults to None. + remove_touching_borders : bool, optional + Whether to remove objects that touch the borders in X and Y. Defaults to False. + remove_touching_borders_z : bool, optional + Whether to remove objects that touch the z-axis borders. Defaults to False. + Returns ------- @@ -107,10 +120,15 @@ def segment_3d_image(imp, title=None, min_thresh=1, min_vol=None, max_vol=None): labeler.setMinSizeCalibrated(min_vol, img) if max_vol: labeler.setMaxSizeCalibrated(max_vol, img) - # Generate labelled segmentation seg = labeler.getLabels(img) seg.setScale(cal.pixelWidth, cal.pixelDepth, cal.getUnits()) + + if remove_touching_borders: + obj = seg.getObjects3DPopulation() + obj.removeObjectsTouchingBorders(seg, remove_touching_borders_z) + seg = ImageHandler.wrap(population3d_to_imgplus(imp, obj)) + if title: seg.setTitle(title) From 0eab3ddd4721d79a86a7d14321d77fbbf3c8dad5 Mon Sep 17 00:00:00 2001 From: Laurent Guerard Date: Thu, 26 Mar 2026 11:28:44 +0100 Subject: [PATCH 2/6] Refactor segment_3d_image to use RemoveBorderLabelsPlugin for borders filtering --- src/imcflibs/imagej/objects3d.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/imcflibs/imagej/objects3d.py b/src/imcflibs/imagej/objects3d.py index 1476c8ae..1c58cabe 100644 --- a/src/imcflibs/imagej/objects3d.py +++ b/src/imcflibs/imagej/objects3d.py @@ -8,6 +8,7 @@ from de.mpicbg.scf.imgtools.image.create.image import ImageCreationUtilities from de.mpicbg.scf.imgtools.image.create.labelmap import WatershedLabeling from ij import IJ +from inra.ijpb.plugins import RemoveBorderLabelsPlugin from mcib3d.geom import Objects3DPopulation from mcib3d.image3d import ImageHandler, ImageLabeller from mcib3d.image3d.processing import MaximaFinder @@ -124,15 +125,20 @@ def segment_3d_image( seg = labeler.getLabels(img) seg.setScale(cal.pixelWidth, cal.pixelDepth, cal.getUnits()) - if remove_touching_borders: - obj = seg.getObjects3DPopulation() - obj.removeObjectsTouchingBorders(seg, remove_touching_borders_z) - seg = ImageHandler.wrap(population3d_to_imgplus(imp, obj)) + seg = RemoveBorderLabelsPlugin().remove( + seg.getImagePlus(), + remove_touching_borders, + remove_touching_borders, + remove_touching_borders, + remove_touching_borders, + remove_touching_borders_z, + remove_touching_borders_z, + ) if title: seg.setTitle(title) - return seg.getImagePlus() + return seg def maxima_finder_3d(imp, min_threshold=0, noise=100, rxy=1.5, rz=1.5): From 703a7cdb6e5b4aa70c3d08b0a663ec7d8ae24e0f Mon Sep 17 00:00:00 2001 From: Niko Ehrenfeuchter Date: Tue, 7 Apr 2026 13:30:34 +0200 Subject: [PATCH 3/6] Exclude segment_3d_image from coverage --- src/imcflibs/imagej/objects3d.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imcflibs/imagej/objects3d.py b/src/imcflibs/imagej/objects3d.py index 1c58cabe..dc70d283 100644 --- a/src/imcflibs/imagej/objects3d.py +++ b/src/imcflibs/imagej/objects3d.py @@ -80,7 +80,7 @@ def segment_3d_image( max_vol=None, remove_touching_borders=False, remove_touching_borders_z=False, -): +): # pragma: no cover (Jython-only) """Segment a 3D binary image to get a labelled stack. Parameters From efec83c1c8c229940a5b7bc45e09a9a5c6191769 Mon Sep 17 00:00:00 2001 From: Niko Ehrenfeuchter Date: Tue, 7 Apr 2026 16:21:11 +0200 Subject: [PATCH 4/6] Add note about updating dependencies in pyproject.toml --- pyproject.toml | 7 +++++++ src/imcflibs/imagej/objects3d.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a5363034..2b2c107b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,7 @@ version = "0.0.0" # - or: python = ">=3.10" [tool.poetry.dependencies] +# IMPORTANT: see the "poetry.lock.md" file when changing dependencies!!! imcf-fiji-mocks = ">=0.13.0" python = ">=2.7" python-micrometa = "^15.2.3" @@ -54,3 +55,9 @@ ignore = [ [tool.ruff.lint.pydocstyle] convention = "numpy" + +[tool.coverage.report] +exclude_also = [ + 'no-cover:jython-only', + 'cover:jython', +] diff --git a/src/imcflibs/imagej/objects3d.py b/src/imcflibs/imagej/objects3d.py index dc70d283..37583767 100644 --- a/src/imcflibs/imagej/objects3d.py +++ b/src/imcflibs/imagej/objects3d.py @@ -80,7 +80,7 @@ def segment_3d_image( max_vol=None, remove_touching_borders=False, remove_touching_borders_z=False, -): # pragma: no cover (Jython-only) +): # cover:jython """Segment a 3D binary image to get a labelled stack. Parameters From 032f9ab3aca9d54e6d8551f770d8ec6120946819 Mon Sep 17 00:00:00 2001 From: Niko Ehrenfeuchter Date: Tue, 7 Apr 2026 16:21:47 +0200 Subject: [PATCH 5/6] Require at least imcf-fiji-mocks 0.14.0 --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index a8994b27..9b0cf3b1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -137,13 +137,13 @@ test = ["pytest (>=6)"] [[package]] name = "imcf-fiji-mocks" -version = "0.13.0" +version = "0.14.0" description = "Mocks collection for Fiji-Python. Zero functional code." optional = false python-versions = ">=2.7" files = [ - {file = "imcf_fiji_mocks-0.13.0-py2.py3-none-any.whl", hash = "sha256:cb6be2b4af480a9340d182c2bccff78f996c0048abbf05380e214a91a2f89bf2"}, - {file = "imcf_fiji_mocks-0.13.0.tar.gz", hash = "sha256:c29f2dc82a0d4e94963a9f7a455f17012ee37aa8eda4d1c9e9565496df50b063"}, + {file = "imcf_fiji_mocks-0.14.0-py2.py3-none-any.whl", hash = "sha256:df50de4e6eb9ba9b2134b67da949f88a74b0e4129824bee37425a72c4a3c4829"}, + {file = "imcf_fiji_mocks-0.14.0.tar.gz", hash = "sha256:2c297a0a24e8e48b05772acb739bb3c57d5621ae3bd40dad37370d033aff1a7b"}, ] [[package]] @@ -345,4 +345,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.10" -content-hash = "f42e21607d534dc04b7be746639e9ed07e70c2ca736844b023b61598df369638" +content-hash = "c97e2a509e4d74b95df8d58a80c5dd69787a34099243c0b6fb5ce7d333404aad" diff --git a/pyproject.toml b/pyproject.toml index 2b2c107b..aeeaff78 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ version = "0.0.0" [tool.poetry.dependencies] # IMPORTANT: see the "poetry.lock.md" file when changing dependencies!!! -imcf-fiji-mocks = ">=0.13.0" +imcf-fiji-mocks = ">=0.14.0" python = ">=2.7" python-micrometa = "^15.2.3" sjlogging = ">=0.5.2" From f215ea5f43f790ef9424af5376fd9d16e23c2c47 Mon Sep 17 00:00:00 2001 From: Niko Ehrenfeuchter Date: Tue, 7 Apr 2026 16:32:59 +0200 Subject: [PATCH 6/6] Attempt to get coverage for the imports --- tests/test_objects3d.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/test_objects3d.py diff --git a/tests/test_objects3d.py b/tests/test_objects3d.py new file mode 100644 index 00000000..a78725e4 --- /dev/null +++ b/tests/test_objects3d.py @@ -0,0 +1,12 @@ +"""Tests for the imcflibs.imagej.objects3d module.""" + +from imcflibs.imagej.objects3d import imgplus_to_population3d +from imcflibs.imagej.objects3d import maxima_finder_3d +from imcflibs.imagej.objects3d import population3d_to_imgplus +from imcflibs.imagej.objects3d import seeded_watershed +from imcflibs.imagej.objects3d import segment_3d_image + + +def test_mock_imports(): + """Test if the mock imports work fine.""" + assert True