From d15427d017201adfdf0c98f791f8885d28d2c817 Mon Sep 17 00:00:00 2001 From: Constantin Pape Date: Wed, 4 Feb 2026 09:46:21 +0100 Subject: [PATCH 1/2] Separate touching instances before export to IMOD --- synapse_net/imod/to_imod.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/synapse_net/imod/to_imod.py b/synapse_net/imod/to_imod.py index a30cbdf..2f2051f 100644 --- a/synapse_net/imod/to_imod.py +++ b/synapse_net/imod/to_imod.py @@ -14,6 +14,7 @@ import numpy as np from scipy.ndimage import distance_transform_edt from skimage.measure import regionprops +from skimage.segmentation import find_boundaries from tqdm import tqdm @@ -27,6 +28,14 @@ def _load_segmentation(segmentation_path, segmentation_key): return seg +def _separate_instances(segmentation): + boundaries = find_boundaries(segmentation, mode="outer") + boundaries &= (segmentation != 0) + segmentation = segmentation.copy() + segmentation[boundaries] = 0 + return segmentation + + # TODO: this has still some issues with some tomograms that has an offset info. # For now, this occurs for the inner ear data tomograms; it works for Fidi's STEM tomograms. # Ben's theory is that this might be due to data form JEOL vs. ThermoFischer microscopes. @@ -37,6 +46,7 @@ def write_segmentation_to_imod( segmentation: Union[str, np.ndarray], output_path: str, segmentation_key: Optional[str] = None, + separate_instances: bool = True, ) -> None: """Write a segmentation to a mod file as closed contour object(s). @@ -45,6 +55,7 @@ def write_segmentation_to_imod( segmentation: The segmentation (either as numpy array or filepath to a .tif file). output_path: The output path where the mod file will be saved. segmentation_key: The key to the segmentation data in case the segmentation is stored in hdf5 files. + separate_instances: Whether to seperate touching instances before the export. """ cmd = "imodauto" cmd_path = shutil.which(cmd) @@ -55,6 +66,8 @@ def write_segmentation_to_imod( segmentation = _load_segmentation(segmentation, segmentation_key) # Binarize the segmentation and flip its axes to match the IMOD axis convention. + if separate_instances: + segmentation = _separate_instances(segmentation) segmentation = (segmentation > 0).astype("uint8") segmentation = np.flip(segmentation, axis=1) @@ -209,13 +222,13 @@ def _pad(inp, n=3): x = _pad(coord[2]) y = _pad(shape[1] - coord[1]) z = _pad(coord[0]) - + else: # (y, x) indexing, single z-plane x = _pad(coord[1]) y = _pad(shape[0] - coord[0]) - z=_pad(0) - + z = _pad(0) + f.write(f"{x}{y}{z}{_pad(radius, 2)}\n") cmd = [cmd, "-si", "-scat", fname, output_path] @@ -227,7 +240,6 @@ def _pad(inp, n=3): run(cmd) - def write_segmentation_to_imod_as_points( mrc_path: str, segmentation: Union[str, np.ndarray], From 4ede5130f17b7f27039bf1e7e3f75e8cffda240a Mon Sep 17 00:00:00 2001 From: Constantin Pape Date: Wed, 4 Feb 2026 09:46:44 +0100 Subject: [PATCH 2/2] Bump version --- synapse_net/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synapse_net/__version__.py b/synapse_net/__version__.py index 6a9beea..3d26edf 100644 --- a/synapse_net/__version__.py +++ b/synapse_net/__version__.py @@ -1 +1 @@ -__version__ = "0.4.0" +__version__ = "0.4.1"