8
8
from subprocess import run
9
9
from typing import Optional , Tuple , Union
10
10
11
+ import h5py
11
12
import imageio .v3 as imageio
12
13
import mrcfile
13
14
import numpy as np
16
17
from tqdm import tqdm
17
18
18
19
20
+ def _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
+
19
30
# TODO: this has still some issues with some tomograms that has an offset info.
20
31
# For now, this occurs for the inner ear data tomograms; it works for Fidi's STEM tomograms.
21
32
# Ben's theory is that this might be due to data form JEOL vs. ThermoFischer microscopes.
@@ -25,22 +36,22 @@ def write_segmentation_to_imod(
25
36
mrc_path : str ,
26
37
segmentation : Union [str , np .ndarray ],
27
38
output_path : str ,
39
+ segmentation_key : Optional [str ] = None ,
28
40
) -> None :
29
41
"""Write a segmentation to a mod file as closed contour objects.
30
42
31
43
Args:
32
44
mrc_path: The filepath to the mrc file from which the segmentation was derived.
33
45
segmentation: The segmentation (either as numpy array or filepath to a .tif file).
34
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.
35
48
"""
36
49
cmd = "imodauto"
37
50
cmd_path = shutil .which (cmd )
38
51
assert cmd_path is not None , f"Could not find the { cmd } imod command."
39
52
40
- # Load the segmentation from a tif file in case a filepath was passed.
41
- if isinstance (segmentation , str ):
42
- assert os .path .exists (segmentation )
43
- segmentation = imageio .imread (segmentation )
53
+ # Load the segmentation case a filepath was passed.
54
+ segmentation = _load_segmentation (segmentation , segmentation_key )
44
55
45
56
# Binarize the segmentation and flip its axes to match the IMOD axis convention.
46
57
segmentation = (segmentation > 0 ).astype ("uint8" )
@@ -187,6 +198,7 @@ def write_segmentation_to_imod_as_points(
187
198
min_radius : Union [int , float ],
188
199
radius_factor : float = 1.0 ,
189
200
estimate_radius_2d : bool = True ,
201
+ segmentation_key : Optional [str ] = None ,
190
202
) -> None :
191
203
"""Write segmentation results to .mod file with imod point annotations.
192
204
@@ -201,6 +213,7 @@ def write_segmentation_to_imod_as_points(
201
213
estimate_radius_2d: If true the distance to boundary for determining the centroid and computing
202
214
the radius will be computed only in 2d rather than in 3d. This can lead to better results
203
215
in case of deformation across the depth axis.
216
+ segmentation_key: The key to the segmentation data in case the segmentation is stored in hdf5 files.
204
217
"""
205
218
206
219
# Read the resolution information from the mrcfile.
@@ -212,7 +225,7 @@ def write_segmentation_to_imod_as_points(
212
225
213
226
# Extract the center coordinates and radii from the segmentation.
214
227
if isinstance (segmentation , str ):
215
- segmentation = imageio . imread (segmentation )
228
+ segmentation = _load_segmentation (segmentation , segmentation_key )
216
229
coordinates , radii = convert_segmentation_to_spheres (
217
230
segmentation , resolution = resolution , radius_factor = radius_factor , estimate_radius_2d = estimate_radius_2d
218
231
)
@@ -221,16 +234,22 @@ def write_segmentation_to_imod_as_points(
221
234
write_points_to_imod (coordinates , radii , segmentation .shape , min_radius , output_path )
222
235
223
236
224
- # TODO we also need to support .rec files ...
225
- def _get_file_paths (input_path , ext = ".mrc" ):
237
+ def _get_file_paths (input_path , ext = (".mrc" , ".rec" )):
226
238
if not os .path .exists (input_path ):
227
- raise Exception (f"Input path not found { input_path } " )
239
+ raise Exception (f"Input path not found { input_path } ." )
240
+
241
+ if isinstance (ext , str ):
242
+ ext = (ext ,)
228
243
229
244
if os .path .isfile (input_path ):
230
245
input_files = [input_path ]
231
246
input_root = None
232
247
else :
233
- input_files = sorted (glob (os .path .join (input_path , "**" , f"*{ ext } " ), recursive = True ))
248
+ input_files = []
249
+ for ex in ext :
250
+ input_files .extend (
251
+ sorted (glob (os .path .join (input_path , "**" , f"*{ ex } " ), recursive = True ))
252
+ )
234
253
input_root = input_path
235
254
236
255
return input_files , input_root
@@ -242,6 +261,7 @@ def export_helper(
242
261
output_root : str ,
243
262
export_function : callable ,
244
263
force : bool = False ,
264
+ segmentation_key : Optional [str ] = None ,
245
265
) -> None :
246
266
"""
247
267
Helper function to run imod export for files in a directory.
@@ -258,9 +278,10 @@ def export_helper(
258
278
the path to the segmentation in a .tif file and the output path as only arguments.
259
279
If you want to pass additional arguments to this function the use 'funtools.partial'
260
280
force: Whether to rerun segmentation for output files that are already present.
281
+ segmentation_key: The key to the segmentation data in case the segmentation is stored in hdf5 files.
261
282
"""
262
283
input_files , input_root = _get_file_paths (input_path )
263
- segmentation_files , _ = _get_file_paths (segmentation_path , ext = ".tif" )
284
+ segmentation_files , _ = _get_file_paths (segmentation_path , ext = ".tif" if segmentation_key is None else ".h5" )
264
285
assert len (input_files ) == len (segmentation_files )
265
286
266
287
for input_path , seg_path in tqdm (zip (input_files , segmentation_files ), total = len (input_files )):
@@ -279,4 +300,4 @@ def export_helper(
279
300
continue
280
301
281
302
os .makedirs (os .path .split (output_path )[0 ], exist_ok = True )
282
- export_function (input_path , seg_path , output_path )
303
+ export_function (input_path , seg_path , output_path , segmentation_key = segmentation_key )
0 commit comments