Skip to content

Commit a10dfbb

Browse files
committed
Merge branch 'devel' into pr/122
2 parents b70ff13 + ad505f8 commit a10dfbb

7 files changed

Lines changed: 116 additions & 15 deletions

File tree

README.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,22 @@ following necessary update sites for this package.
5656
- TrackMate-MorpholibJ
5757

5858
The **`IMCF Uni Basel`** update-site will always provide the latest compatible
59-
combination of *official*`.jar` file to use this package.
59+
combination of *official* `.jar` files to use this package.
60+
61+
### Manual Downloads for OMERO
62+
63+
In addition to the update sites, two manual downloads concerning OMERO are
64+
necessary:
65+
66+
- [simple-omero-client]
67+
- [omero-insight]
6068

6169
### 🏗 Alternative: SciJava Maven Package 👷
6270

6371
💡 **IMPORTANT:** 💡 same as for the *default* installation previously
64-
described, you will need to enable **all Update Sites listed above** in your
65-
Fiji as well when using the method described here!
72+
described, you will need to enable **all Update Sites listed above** (and
73+
obviously the respective OMERO downloads) in your Fiji as well when using the
74+
method described here!
6675

6776
The most up-to-date `.jar` (or any other published version, including
6877
pre-releases) for this package can be always found on the [Scijava Maven
@@ -122,3 +131,5 @@ correct_and_project(raw_image, out_path, model, "Maximum", ".ics")
122131
[apidocs]: https://imcf.one/apidocs/imcflibs/imcflibs.html
123132
[pdoc]: https://pdoc.dev/
124133
[pypi]: https://pypi.org/project/imcflibs/
134+
[simple-omero-client]: https://github.com/GReD-Clermont/simple-omero-client
135+
[omero-insight]: https://github.com/ome/omero-insight

poetry.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ version = "0.0.0"
2020
# - or: python = ">=3.10"
2121

2222
[tool.poetry.dependencies]
23-
imcf-fiji-mocks = ">=0.13.0"
23+
# IMPORTANT: see the "poetry.lock.md" file when changing dependencies!!!
24+
imcf-fiji-mocks = ">=0.14.0"
2425
python = ">=2.7"
2526
python-micrometa = "^15.2.3"
2627
sjlogging = ">=0.5.2"
@@ -54,3 +55,9 @@ ignore = [
5455

5556
[tool.ruff.lint.pydocstyle]
5657
convention = "numpy"
58+
59+
[tool.coverage.report]
60+
exclude_also = [
61+
'no-cover:jython-only',
62+
'cover:jython',
63+
]

src/imcflibs/imagej/misc.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,13 @@
1010

1111
from ij import IJ # pylint: disable-msg=import-error
1212
from ij.plugin import Duplicator, ImageCalculator, StackWriter
13+
from org.scijava.widget import TextWidget, WidgetStyle
1314

1415
from .. import pathtools
1516
from ..log import LOG as log
1617
from . import bioformats as bf
1718
from . import prefs
1819

19-
from org.scijava.widget import WidgetStyle
20-
from org.scijava.widget import TextWidget
21-
2220

2321
def show_status(msg):
2422
"""Update the ImageJ status bar and issue a log message.
@@ -533,7 +531,9 @@ def write_ordereddict_to_csv(out_file, content):
533531
dict_writer.writerows(content)
534532

535533

536-
def save_image_in_format(imp, format, out_dir, series, pad_number, split_channels, suffix=""):
534+
def save_image_in_format(
535+
imp, format, out_dir, series, pad_number, split_channels, suffix=""
536+
):
537537
"""Save an ImagePlus object in the specified format.
538538
539539
This function provides flexible options for saving ImageJ images in various
@@ -737,3 +737,32 @@ def run_imarisconvert(file_path, pixel_calibration=None, output_folder=""):
737737
else:
738738
timed_log("Error converting [%s]: %d" % (file_path, result))
739739

740+
741+
def bytes_to_human_readable(size):
742+
"""Convert a byte count to a human-readable string using binary units.
743+
744+
Parameters
745+
----------
746+
size : int
747+
Byte size (number of bytes).
748+
749+
Returns
750+
-------
751+
str
752+
Human-friendly size string, e.g. `"512.0 bytes"`, `"2.0 KB"`,
753+
`"1.0 MB"`.
754+
755+
Notes
756+
-----
757+
- Uses powers of 1024 (KB = 1024 bytes).
758+
- Always returns a string with one decimal place and the unit.
759+
"""
760+
761+
for unit in ["bytes", "KB", "MB", "GB", "TB"]:
762+
if size < 1024.0:
763+
return "%3.1f %s" % (size, unit)
764+
size /= 1024.0
765+
766+
# If the value is larger than the largest unit, fall back to TB with
767+
# the current value (already divided accordingly).
768+
return "%3.1f %s" % (size, "TB")

src/imcflibs/imagej/objects3d.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from de.mpicbg.scf.imgtools.image.create.image import ImageCreationUtilities
99
from de.mpicbg.scf.imgtools.image.create.labelmap import WatershedLabeling
1010
from ij import IJ
11+
from inra.ijpb.plugins import RemoveBorderLabelsPlugin
1112
from mcib3d.geom import Objects3DPopulation
1213
from mcib3d.image3d import ImageHandler, ImageLabeller
1314
from mcib3d.image3d.processing import MaximaFinder
@@ -71,7 +72,15 @@ def imgplus_to_population3d(imp):
7172
return Objects3DPopulation(img)
7273

7374

74-
def segment_3d_image(imp, title=None, min_thresh=1, min_vol=None, max_vol=None):
75+
def segment_3d_image(
76+
imp,
77+
title=None,
78+
min_thresh=1,
79+
min_vol=None,
80+
max_vol=None,
81+
remove_touching_borders=False,
82+
remove_touching_borders_z=False,
83+
): # cover:jython
7584
"""Segment a 3D binary image to get a labelled stack.
7685
7786
Parameters
@@ -90,6 +99,11 @@ def segment_3d_image(imp, title=None, min_thresh=1, min_vol=None, max_vol=None):
9099
max_vol : int, optional
91100
Maximum volume (in voxels) above which objects get filtered.
92101
Defaults to None.
102+
remove_touching_borders : bool, optional
103+
Whether to remove objects that touch the borders in X and Y. Defaults to False.
104+
remove_touching_borders_z : bool, optional
105+
Whether to remove objects that touch the z-axis borders. Defaults to False.
106+
93107
94108
Returns
95109
-------
@@ -107,14 +121,24 @@ def segment_3d_image(imp, title=None, min_thresh=1, min_vol=None, max_vol=None):
107121
labeler.setMinSizeCalibrated(min_vol, img)
108122
if max_vol:
109123
labeler.setMaxSizeCalibrated(max_vol, img)
110-
111124
# Generate labelled segmentation
112125
seg = labeler.getLabels(img)
113126
seg.setScale(cal.pixelWidth, cal.pixelDepth, cal.getUnits())
127+
128+
seg = RemoveBorderLabelsPlugin().remove(
129+
seg.getImagePlus(),
130+
remove_touching_borders,
131+
remove_touching_borders,
132+
remove_touching_borders,
133+
remove_touching_borders,
134+
remove_touching_borders_z,
135+
remove_touching_borders_z,
136+
)
137+
114138
if title:
115139
seg.setTitle(title)
116140

117-
return seg.getImagePlus()
141+
return seg
118142

119143

120144
def maxima_finder_3d(imp, min_threshold=0, noise=100, rxy=1.5, rz=1.5):

tests/test_misc.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""Tests for `imcflibs.imagej.misc` utility functions."""
2+
3+
from imcflibs.imagej.misc import bytes_to_human_readable
4+
5+
6+
def test_bytes_to_human_readable_simple():
7+
"""Ensure common sizes are formatted into human-readable strings."""
8+
assert bytes_to_human_readable(500) == "500.0 bytes"
9+
assert bytes_to_human_readable(2048) == "2.0 KB"
10+
assert bytes_to_human_readable(1024 * 1024) == "1.0 MB"
11+
assert bytes_to_human_readable(5 * 1024**3) == "5.0 GB"
12+
13+
14+
def test_bytes_to_human_readable_large():
15+
"""Verify formatting for large sizes such as terabytes."""
16+
# 1.5 TB in bytes should format as 1.5 TB
17+
size = int(1.5 * (1024**4))
18+
assert bytes_to_human_readable(size) == "1.5 TB"

tests/test_objects3d.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"""Tests for the imcflibs.imagej.objects3d module."""
2+
3+
from imcflibs.imagej.objects3d import imgplus_to_population3d
4+
from imcflibs.imagej.objects3d import maxima_finder_3d
5+
from imcflibs.imagej.objects3d import population3d_to_imgplus
6+
from imcflibs.imagej.objects3d import seeded_watershed
7+
from imcflibs.imagej.objects3d import segment_3d_image
8+
9+
10+
def test_mock_imports():
11+
"""Test if the mock imports work fine."""
12+
assert True

0 commit comments

Comments
 (0)