synapse_net.imod.to_imod

  1import multiprocessing
  2import os
  3import shutil
  4import tempfile
  5
  6from concurrent import futures
  7from glob import glob
  8from subprocess import run
  9from typing import Optional, Tuple, Union
 10
 11import h5py
 12import imageio.v3 as imageio
 13import mrcfile
 14import numpy as np
 15from scipy.ndimage import distance_transform_edt
 16from skimage.measure import regionprops
 17from tqdm import tqdm
 18
 19
 20def _load_segmentation(segmentation_path, segmentation_key):
 21    assert os.path.exists(segmentation_path), segmentation_path
 22    if segmentation_key is None:
 23        seg = imageio.imread(segmentation_path)
 24    else:
 25        with h5py.File(segmentation_path, "r") as f:
 26            seg = f[segmentation_key][:]
 27    return seg
 28
 29
 30# TODO: this has still some issues with some tomograms that has an offset info.
 31# For now, this occurs for the inner ear data tomograms; it works for Fidi's STEM tomograms.
 32# Ben's theory is that this might be due to data form JEOL vs. ThermoFischer microscopes.
 33# To test this I can check how it works for data from Maus et al. / Imig et al., which were taken on a JEOL.
 34# Can also check out the mrc documentation here: https://www.ccpem.ac.uk/mrc_format/mrc2014.php
 35def write_segmentation_to_imod(
 36    mrc_path: str,
 37    segmentation: Union[str, np.ndarray],
 38    output_path: str,
 39    segmentation_key: Optional[str] = None,
 40) -> None:
 41    """Write a segmentation to a mod file as closed contour object(s).
 42
 43    Args:
 44        mrc_path: The filepath to the mrc file from which the segmentation was derived.
 45        segmentation: The segmentation (either as numpy array or filepath to a .tif file).
 46        output_path: The output path where the mod file will be saved.
 47        segmentation_key: The key to the segmentation data in case the segmentation is stored in hdf5 files.
 48    """
 49    cmd = "imodauto"
 50    cmd_path = shutil.which(cmd)
 51    assert cmd_path is not None, f"Could not find the {cmd} imod command."
 52
 53    # Load the segmentation case a filepath was passed.
 54    if isinstance(segmentation, str):
 55        segmentation = _load_segmentation(segmentation, segmentation_key)
 56
 57    # Binarize the segmentation and flip its axes to match the IMOD axis convention.
 58    segmentation = (segmentation > 0).astype("uint8")
 59    segmentation = np.flip(segmentation, axis=1)
 60
 61    # Read the voxel size and origin information from the mrc file.
 62    assert os.path.exists(mrc_path)
 63    with mrcfile.open(mrc_path, mode="r") as f:
 64        voxel_size = f.voxel_size
 65        nx, ny, nz = f.header.nxstart, f.header.nystart, f.header.nzstart
 66        origin = f.header.origin
 67
 68    # Write the input for imodauto to a temporary mrc file.
 69    with tempfile.NamedTemporaryFile(suffix=".mrc") as f:
 70        tmp_path = f.name
 71
 72        mrcfile.new(tmp_path, data=segmentation, overwrite=True)
 73        # Write the voxel_size and origin infomration.
 74        with mrcfile.open(tmp_path, mode="r+") as f:
 75            f.voxel_size = voxel_size
 76
 77            f.header.nxstart = nx
 78            f.header.nystart = ny
 79            f.header.nzstart = nz
 80            f.header.origin = (0.0, 0.0, 0.0) * 3 if origin is None else origin
 81
 82            f.update_header_from_data()
 83
 84        # Run the command.
 85        cmd_list = [cmd, "-E", "1", "-u", tmp_path, output_path]
 86        run(cmd_list)
 87
 88
 89def convert_segmentation_to_spheres(
 90    segmentation: np.ndarray,
 91    verbose: bool = False,
 92    num_workers: Optional[int] = None,
 93    resolution: Optional[Tuple[float, float, float]] = None,
 94    radius_factor: float = 1.0,
 95    estimate_radius_2d: bool = True,
 96    props: Optional[list] = None,
 97) -> Tuple[np.ndarray, np.ndarray]:
 98    """Extract spheres parameterized by center and radius from a segmentation.
 99
100    Args:
101        segmentation: The segmentation.
102        verbose: Whether to print a progress bar.
103        num_workers: Number of workers to use for parallelization.
104        resolution: The physical resolution of the data.
105        radius_factor: Factor for increasing the radius to account for too small exported spheres.
106        estimate_radius_2d: If true the distance to boundary for determining the centroid and computing
107            the radius will be computed only in 2d rather than in 3d. This can lead to better results
108            in case of deformation across the depth axis.
109        props: Optional list of regionprops
110
111    Returns:
112        The center coordinates.
113        The radii.
114    """
115    num_workers = multiprocessing.cpu_count() if num_workers is None else num_workers
116    if props is None:
117        props = regionprops(segmentation)
118
119    def coords_and_rads(prop):
120        seg_id = prop.label
121        bbox = prop.bbox
122        ndim = len(bbox) // 2
123
124        # Handle 2D bounding box
125        if len(bbox) == 4:
126            bb = np.s_[bbox[0]:bbox[2], bbox[1]:bbox[3]]
127            mask = segmentation[bb] == seg_id
128            if resolution:
129                dists = distance_transform_edt(mask, sampling=resolution)
130            else:
131                dists = distance_transform_edt(mask)
132
133        # Handle 3D bounding box
134        elif len(bbox) == 6:
135            bb = np.s_[bbox[0]:bbox[3], bbox[1]:bbox[4], bbox[2]:bbox[5]]
136            mask = segmentation[bb] == seg_id
137
138            if estimate_radius_2d:
139                if resolution:
140                    dists = np.array([distance_transform_edt(ma, sampling=resolution[1:]) for ma in mask])
141                else:
142                    dists = np.array([distance_transform_edt(ma) for ma in mask])
143            else:
144                dists = distance_transform_edt(mask, sampling=resolution)
145        else:
146            raise ValueError(f"Unsupported bounding box dimensions: {len(bbox)}")
147
148        max_coord = np.unravel_index(np.argmax(dists), mask.shape)
149        radius = dists[max_coord] * radius_factor
150
151        offset = np.array(bbox[:ndim])
152
153        coord = np.array(max_coord) + offset
154
155        return coord, radius
156
157    with futures.ThreadPoolExecutor(num_workers) as tp:
158        res = list(tqdm(
159            tp.map(coords_and_rads, props), disable=not verbose, total=len(props),
160            desc="Compute coordinates and radii"
161        ))
162
163    coords = [re[0] for re in res]
164    rads = [re[1] for re in res]
165    return np.array(coords), np.array(rads)
166
167
168def write_points_to_imod(
169    coordinates: np.ndarray,
170    radii: np.ndarray,
171    shape: Tuple[int, int, int],
172    min_radius: Union[float, int],
173    output_path: str,
174    color: Optional[Tuple[int, int, int]] = None,
175) -> None:
176    """Write point annotations to a .mod file for IMOD.
177
178    Args:
179        coordinates: Array with the point coordinates.
180        radii: Array with the point radii.
181        shape: Shape of the volume to be exported.
182        min_radius: Minimum radius for export.
183        output_path: Where to save the .mod file.
184        color: Optional color for writing out the points.
185    """
186    cmd = "point2model"
187    cmd_path = shutil.which(cmd)
188    assert cmd_path is not None, f"Could not find the {cmd} imod command."
189
190    def _pad(inp, n=3):
191        inp = int(round(inp))
192        plen = 6 + (n - len(str(inp)))
193        pw = plen * " "
194        return f"{pw}{inp}.00"
195
196    with tempfile.NamedTemporaryFile() as tmp_file:
197        fname = tmp_file.name
198        with open(fname, "w") as f:
199            for coord, radius in zip(coordinates, radii):
200                if radius < min_radius:
201                    continue
202                # IMOD needs peculiar whitespace padding
203                x = _pad(coord[2])
204                y = _pad(shape[1] - coord[1])
205                z = _pad(coord[0])
206                f.write(f"{x}{y}{z}{_pad(radius, 2)}\n")
207
208        cmd = [cmd, "-si", "-scat", fname, output_path]
209        if color is not None:
210            assert len(color) == 3
211            r, g, b = [str(co) for co in color]
212            cmd += ["-co", f"{r} {g} {b}"]
213
214        run(cmd)
215
216
217def write_segmentation_to_imod_as_points(
218    mrc_path: str,
219    segmentation: Union[str, np.ndarray],
220    output_path: str,
221    min_radius: Union[int, float],
222    radius_factor: float = 1.0,
223    estimate_radius_2d: bool = True,
224    segmentation_key: Optional[str] = None,
225) -> None:
226    """Write segmentation results to .mod file with imod point annotations.
227
228    This approximates each segmented object as a sphere.
229
230    Args:
231        mrc_path: Filepath to the mrc volume that was segmented.
232        segmentation: The segmentation (either as numpy array or filepath to a .tif file).
233        output_path: Where to save the .mod file.
234        min_radius: Minimum radius for export.
235        radius_factor: Factor for increasing the radius to account for too small exported spheres.
236        estimate_radius_2d: If true the distance to boundary for determining the centroid and computing
237            the radius will be computed only in 2d rather than in 3d. This can lead to better results
238            in case of deformation across the depth axis.
239        segmentation_key: The key to the segmentation data in case the segmentation is stored in hdf5 files.
240    """
241
242    # Read the resolution information from the mrcfile.
243    with mrcfile.open(mrc_path, "r") as f:
244        resolution = f.voxel_size.tolist()
245
246    # The resolution is stored in angstrom, we convert it to nanometer.
247    resolution = [res / 10 for res in resolution]
248
249    # Extract the center coordinates and radii from the segmentation.
250    if isinstance(segmentation, str):
251        segmentation = _load_segmentation(segmentation, segmentation_key)
252    coordinates, radii = convert_segmentation_to_spheres(
253        segmentation, resolution=resolution, radius_factor=radius_factor, estimate_radius_2d=estimate_radius_2d
254    )
255
256    # Write the point annotations to imod.
257    write_points_to_imod(coordinates, radii, segmentation.shape, min_radius, output_path)
258
259
260def _get_file_paths(input_path, ext=(".mrc", ".rec")):
261    if not os.path.exists(input_path):
262        raise Exception(f"Input path not found {input_path}.")
263
264    if isinstance(ext, str):
265        ext = (ext,)
266
267    if os.path.isfile(input_path):
268        input_files = [input_path]
269        input_root = None
270    else:
271        input_files = []
272        for ex in ext:
273            input_files.extend(
274                sorted(glob(os.path.join(input_path, "**", f"*{ex}"), recursive=True))
275            )
276        input_root = input_path
277
278    return input_files, input_root
279
280
281def export_helper(
282    input_path: str,
283    segmentation_path: str,
284    output_root: str,
285    export_function: callable,
286    force: bool = False,
287    segmentation_key: Optional[str] = None,
288) -> None:
289    """
290    Helper function to run imod export for files in a directory.
291
292    Args:
293        input_path: The path to the input data.
294            Can either be a folder. In this case all mrc files below the folder will be exported.
295            Or can be a single mrc file. In this case only this mrc file will be segmented.
296        segmentation_path: Filepath to the segmentation results.
297            The filestructure must exactly match `input_path`.
298        output_root: The path to the output directory where the export results will be saved.
299        export_function: The function performing the export to the desired imod format.
300            This function must take the path to the input in a .mrc file,
301            the path to the segmentation in a .tif file and the output path as only arguments.
302            If you want to pass additional arguments to this function the use 'funtools.partial'
303        force: Whether to rerun segmentation for output files that are already present.
304        segmentation_key: The key to the segmentation data in case the segmentation is stored in hdf5 files.
305    """
306    input_files, input_root = _get_file_paths(input_path)
307    segmentation_files, _ = _get_file_paths(segmentation_path, ext=".tif" if segmentation_key is None else ".h5")
308    assert len(input_files) == len(segmentation_files)
309
310    for input_path, seg_path in tqdm(zip(input_files, segmentation_files), total=len(input_files)):
311        # Determine the output file name.
312        input_folder, input_name = os.path.split(input_path)
313        fname = os.path.splitext(input_name)[0] + ".mod"
314        if input_root is None:
315            output_path = os.path.join(output_root, fname)
316        else:  # If we have nested input folders then we preserve the folder structure in the output.
317            rel_folder = os.path.relpath(input_folder, input_root)
318            output_path = os.path.join(output_root, rel_folder, fname)
319
320        # Check if the output path is already present.
321        # If it is we skip the prediction, unless force was set to true.
322        if os.path.exists(output_path) and not force:
323            continue
324
325        os.makedirs(os.path.split(output_path)[0], exist_ok=True)
326        export_function(input_path, seg_path, output_path, segmentation_key=segmentation_key)
def write_segmentation_to_imod( mrc_path: str, segmentation: Union[str, numpy.ndarray], output_path: str, segmentation_key: Optional[str] = None) -> None:
36def write_segmentation_to_imod(
37    mrc_path: str,
38    segmentation: Union[str, np.ndarray],
39    output_path: str,
40    segmentation_key: Optional[str] = None,
41) -> None:
42    """Write a segmentation to a mod file as closed contour object(s).
43
44    Args:
45        mrc_path: The filepath to the mrc file from which the segmentation was derived.
46        segmentation: The segmentation (either as numpy array or filepath to a .tif file).
47        output_path: The output path where the mod file will be saved.
48        segmentation_key: The key to the segmentation data in case the segmentation is stored in hdf5 files.
49    """
50    cmd = "imodauto"
51    cmd_path = shutil.which(cmd)
52    assert cmd_path is not None, f"Could not find the {cmd} imod command."
53
54    # Load the segmentation case a filepath was passed.
55    if isinstance(segmentation, str):
56        segmentation = _load_segmentation(segmentation, segmentation_key)
57
58    # Binarize the segmentation and flip its axes to match the IMOD axis convention.
59    segmentation = (segmentation > 0).astype("uint8")
60    segmentation = np.flip(segmentation, axis=1)
61
62    # Read the voxel size and origin information from the mrc file.
63    assert os.path.exists(mrc_path)
64    with mrcfile.open(mrc_path, mode="r") as f:
65        voxel_size = f.voxel_size
66        nx, ny, nz = f.header.nxstart, f.header.nystart, f.header.nzstart
67        origin = f.header.origin
68
69    # Write the input for imodauto to a temporary mrc file.
70    with tempfile.NamedTemporaryFile(suffix=".mrc") as f:
71        tmp_path = f.name
72
73        mrcfile.new(tmp_path, data=segmentation, overwrite=True)
74        # Write the voxel_size and origin infomration.
75        with mrcfile.open(tmp_path, mode="r+") as f:
76            f.voxel_size = voxel_size
77
78            f.header.nxstart = nx
79            f.header.nystart = ny
80            f.header.nzstart = nz
81            f.header.origin = (0.0, 0.0, 0.0) * 3 if origin is None else origin
82
83            f.update_header_from_data()
84
85        # Run the command.
86        cmd_list = [cmd, "-E", "1", "-u", tmp_path, output_path]
87        run(cmd_list)

Write a segmentation to a mod file as closed contour object(s).

Arguments:
  • mrc_path: The filepath to the mrc file from which the segmentation was derived.
  • 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.
def convert_segmentation_to_spheres( segmentation: numpy.ndarray, verbose: bool = False, num_workers: Optional[int] = None, resolution: Optional[Tuple[float, float, float]] = None, radius_factor: float = 1.0, estimate_radius_2d: bool = True, props: Optional[list] = None) -> Tuple[numpy.ndarray, numpy.ndarray]:
 90def convert_segmentation_to_spheres(
 91    segmentation: np.ndarray,
 92    verbose: bool = False,
 93    num_workers: Optional[int] = None,
 94    resolution: Optional[Tuple[float, float, float]] = None,
 95    radius_factor: float = 1.0,
 96    estimate_radius_2d: bool = True,
 97    props: Optional[list] = None,
 98) -> Tuple[np.ndarray, np.ndarray]:
 99    """Extract spheres parameterized by center and radius from a segmentation.
100
101    Args:
102        segmentation: The segmentation.
103        verbose: Whether to print a progress bar.
104        num_workers: Number of workers to use for parallelization.
105        resolution: The physical resolution of the data.
106        radius_factor: Factor for increasing the radius to account for too small exported spheres.
107        estimate_radius_2d: If true the distance to boundary for determining the centroid and computing
108            the radius will be computed only in 2d rather than in 3d. This can lead to better results
109            in case of deformation across the depth axis.
110        props: Optional list of regionprops
111
112    Returns:
113        The center coordinates.
114        The radii.
115    """
116    num_workers = multiprocessing.cpu_count() if num_workers is None else num_workers
117    if props is None:
118        props = regionprops(segmentation)
119
120    def coords_and_rads(prop):
121        seg_id = prop.label
122        bbox = prop.bbox
123        ndim = len(bbox) // 2
124
125        # Handle 2D bounding box
126        if len(bbox) == 4:
127            bb = np.s_[bbox[0]:bbox[2], bbox[1]:bbox[3]]
128            mask = segmentation[bb] == seg_id
129            if resolution:
130                dists = distance_transform_edt(mask, sampling=resolution)
131            else:
132                dists = distance_transform_edt(mask)
133
134        # Handle 3D bounding box
135        elif len(bbox) == 6:
136            bb = np.s_[bbox[0]:bbox[3], bbox[1]:bbox[4], bbox[2]:bbox[5]]
137            mask = segmentation[bb] == seg_id
138
139            if estimate_radius_2d:
140                if resolution:
141                    dists = np.array([distance_transform_edt(ma, sampling=resolution[1:]) for ma in mask])
142                else:
143                    dists = np.array([distance_transform_edt(ma) for ma in mask])
144            else:
145                dists = distance_transform_edt(mask, sampling=resolution)
146        else:
147            raise ValueError(f"Unsupported bounding box dimensions: {len(bbox)}")
148
149        max_coord = np.unravel_index(np.argmax(dists), mask.shape)
150        radius = dists[max_coord] * radius_factor
151
152        offset = np.array(bbox[:ndim])
153
154        coord = np.array(max_coord) + offset
155
156        return coord, radius
157
158    with futures.ThreadPoolExecutor(num_workers) as tp:
159        res = list(tqdm(
160            tp.map(coords_and_rads, props), disable=not verbose, total=len(props),
161            desc="Compute coordinates and radii"
162        ))
163
164    coords = [re[0] for re in res]
165    rads = [re[1] for re in res]
166    return np.array(coords), np.array(rads)

Extract spheres parameterized by center and radius from a segmentation.

Arguments:
  • segmentation: The segmentation.
  • verbose: Whether to print a progress bar.
  • num_workers: Number of workers to use for parallelization.
  • resolution: The physical resolution of the data.
  • radius_factor: Factor for increasing the radius to account for too small exported spheres.
  • estimate_radius_2d: If true the distance to boundary for determining the centroid and computing the radius will be computed only in 2d rather than in 3d. This can lead to better results in case of deformation across the depth axis.
  • props: Optional list of regionprops
Returns:

The center coordinates. The radii.

def write_points_to_imod( coordinates: numpy.ndarray, radii: numpy.ndarray, shape: Tuple[int, int, int], min_radius: Union[float, int], output_path: str, color: Optional[Tuple[int, int, int]] = None) -> None:
169def write_points_to_imod(
170    coordinates: np.ndarray,
171    radii: np.ndarray,
172    shape: Tuple[int, int, int],
173    min_radius: Union[float, int],
174    output_path: str,
175    color: Optional[Tuple[int, int, int]] = None,
176) -> None:
177    """Write point annotations to a .mod file for IMOD.
178
179    Args:
180        coordinates: Array with the point coordinates.
181        radii: Array with the point radii.
182        shape: Shape of the volume to be exported.
183        min_radius: Minimum radius for export.
184        output_path: Where to save the .mod file.
185        color: Optional color for writing out the points.
186    """
187    cmd = "point2model"
188    cmd_path = shutil.which(cmd)
189    assert cmd_path is not None, f"Could not find the {cmd} imod command."
190
191    def _pad(inp, n=3):
192        inp = int(round(inp))
193        plen = 6 + (n - len(str(inp)))
194        pw = plen * " "
195        return f"{pw}{inp}.00"
196
197    with tempfile.NamedTemporaryFile() as tmp_file:
198        fname = tmp_file.name
199        with open(fname, "w") as f:
200            for coord, radius in zip(coordinates, radii):
201                if radius < min_radius:
202                    continue
203                # IMOD needs peculiar whitespace padding
204                x = _pad(coord[2])
205                y = _pad(shape[1] - coord[1])
206                z = _pad(coord[0])
207                f.write(f"{x}{y}{z}{_pad(radius, 2)}\n")
208
209        cmd = [cmd, "-si", "-scat", fname, output_path]
210        if color is not None:
211            assert len(color) == 3
212            r, g, b = [str(co) for co in color]
213            cmd += ["-co", f"{r} {g} {b}"]
214
215        run(cmd)

Write point annotations to a .mod file for IMOD.

Arguments:
  • coordinates: Array with the point coordinates.
  • radii: Array with the point radii.
  • shape: Shape of the volume to be exported.
  • min_radius: Minimum radius for export.
  • output_path: Where to save the .mod file.
  • color: Optional color for writing out the points.
def write_segmentation_to_imod_as_points( mrc_path: str, segmentation: Union[str, numpy.ndarray], output_path: str, min_radius: Union[int, float], radius_factor: float = 1.0, estimate_radius_2d: bool = True, segmentation_key: Optional[str] = None) -> None:
218def write_segmentation_to_imod_as_points(
219    mrc_path: str,
220    segmentation: Union[str, np.ndarray],
221    output_path: str,
222    min_radius: Union[int, float],
223    radius_factor: float = 1.0,
224    estimate_radius_2d: bool = True,
225    segmentation_key: Optional[str] = None,
226) -> None:
227    """Write segmentation results to .mod file with imod point annotations.
228
229    This approximates each segmented object as a sphere.
230
231    Args:
232        mrc_path: Filepath to the mrc volume that was segmented.
233        segmentation: The segmentation (either as numpy array or filepath to a .tif file).
234        output_path: Where to save the .mod file.
235        min_radius: Minimum radius for export.
236        radius_factor: Factor for increasing the radius to account for too small exported spheres.
237        estimate_radius_2d: If true the distance to boundary for determining the centroid and computing
238            the radius will be computed only in 2d rather than in 3d. This can lead to better results
239            in case of deformation across the depth axis.
240        segmentation_key: The key to the segmentation data in case the segmentation is stored in hdf5 files.
241    """
242
243    # Read the resolution information from the mrcfile.
244    with mrcfile.open(mrc_path, "r") as f:
245        resolution = f.voxel_size.tolist()
246
247    # The resolution is stored in angstrom, we convert it to nanometer.
248    resolution = [res / 10 for res in resolution]
249
250    # Extract the center coordinates and radii from the segmentation.
251    if isinstance(segmentation, str):
252        segmentation = _load_segmentation(segmentation, segmentation_key)
253    coordinates, radii = convert_segmentation_to_spheres(
254        segmentation, resolution=resolution, radius_factor=radius_factor, estimate_radius_2d=estimate_radius_2d
255    )
256
257    # Write the point annotations to imod.
258    write_points_to_imod(coordinates, radii, segmentation.shape, min_radius, output_path)

Write segmentation results to .mod file with imod point annotations.

This approximates each segmented object as a sphere.

Arguments:
  • mrc_path: Filepath to the mrc volume that was segmented.
  • segmentation: The segmentation (either as numpy array or filepath to a .tif file).
  • output_path: Where to save the .mod file.
  • min_radius: Minimum radius for export.
  • radius_factor: Factor for increasing the radius to account for too small exported spheres.
  • estimate_radius_2d: If true the distance to boundary for determining the centroid and computing the radius will be computed only in 2d rather than in 3d. This can lead to better results in case of deformation across the depth axis.
  • segmentation_key: The key to the segmentation data in case the segmentation is stored in hdf5 files.
def export_helper( input_path: str, segmentation_path: str, output_root: str, export_function: <built-in function callable>, force: bool = False, segmentation_key: Optional[str] = None) -> None:
282def export_helper(
283    input_path: str,
284    segmentation_path: str,
285    output_root: str,
286    export_function: callable,
287    force: bool = False,
288    segmentation_key: Optional[str] = None,
289) -> None:
290    """
291    Helper function to run imod export for files in a directory.
292
293    Args:
294        input_path: The path to the input data.
295            Can either be a folder. In this case all mrc files below the folder will be exported.
296            Or can be a single mrc file. In this case only this mrc file will be segmented.
297        segmentation_path: Filepath to the segmentation results.
298            The filestructure must exactly match `input_path`.
299        output_root: The path to the output directory where the export results will be saved.
300        export_function: The function performing the export to the desired imod format.
301            This function must take the path to the input in a .mrc file,
302            the path to the segmentation in a .tif file and the output path as only arguments.
303            If you want to pass additional arguments to this function the use 'funtools.partial'
304        force: Whether to rerun segmentation for output files that are already present.
305        segmentation_key: The key to the segmentation data in case the segmentation is stored in hdf5 files.
306    """
307    input_files, input_root = _get_file_paths(input_path)
308    segmentation_files, _ = _get_file_paths(segmentation_path, ext=".tif" if segmentation_key is None else ".h5")
309    assert len(input_files) == len(segmentation_files)
310
311    for input_path, seg_path in tqdm(zip(input_files, segmentation_files), total=len(input_files)):
312        # Determine the output file name.
313        input_folder, input_name = os.path.split(input_path)
314        fname = os.path.splitext(input_name)[0] + ".mod"
315        if input_root is None:
316            output_path = os.path.join(output_root, fname)
317        else:  # If we have nested input folders then we preserve the folder structure in the output.
318            rel_folder = os.path.relpath(input_folder, input_root)
319            output_path = os.path.join(output_root, rel_folder, fname)
320
321        # Check if the output path is already present.
322        # If it is we skip the prediction, unless force was set to true.
323        if os.path.exists(output_path) and not force:
324            continue
325
326        os.makedirs(os.path.split(output_path)[0], exist_ok=True)
327        export_function(input_path, seg_path, output_path, segmentation_key=segmentation_key)

Helper function to run imod export for files in a directory.

Arguments:
  • input_path: The path to the input data. Can either be a folder. In this case all mrc files below the folder will be exported. Or can be a single mrc file. In this case only this mrc file will be segmented.
  • segmentation_path: Filepath to the segmentation results. The filestructure must exactly match input_path.
  • output_root: The path to the output directory where the export results will be saved.
  • export_function: The function performing the export to the desired imod format. This function must take the path to the input in a .mrc file, the path to the segmentation in a .tif file and the output path as only arguments. If you want to pass additional arguments to this function the use 'funtools.partial'
  • force: Whether to rerun segmentation for output files that are already present.
  • segmentation_key: The key to the segmentation data in case the segmentation is stored in hdf5 files.