88from subprocess import run
99from typing import Optional , Tuple , Union
1010
11+ import h5py
1112import imageio .v3 as imageio
1213import mrcfile
1314import numpy as np
1617from tqdm import tqdm
1718
1819
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+
1930# TODO: this has still some issues with some tomograms that has an offset info.
2031# For now, this occurs for the inner ear data tomograms; it works for Fidi's STEM tomograms.
2132# 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(
2536 mrc_path : str ,
2637 segmentation : Union [str , np .ndarray ],
2738 output_path : str ,
39+ segmentation_key : Optional [str ] = None ,
2840) -> None :
2941 """Write a segmentation to a mod file as closed contour objects.
3042
3143 Args:
3244 mrc_path: The filepath to the mrc file from which the segmentation was derived.
3345 segmentation: The segmentation (either as numpy array or filepath to a .tif file).
3446 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.
3548 """
3649 cmd = "imodauto"
3750 cmd_path = shutil .which (cmd )
3851 assert cmd_path is not None , f"Could not find the { cmd } imod command."
3952
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 )
4455
4556 # Binarize the segmentation and flip its axes to match the IMOD axis convention.
4657 segmentation = (segmentation > 0 ).astype ("uint8" )
@@ -187,6 +198,7 @@ def write_segmentation_to_imod_as_points(
187198 min_radius : Union [int , float ],
188199 radius_factor : float = 1.0 ,
189200 estimate_radius_2d : bool = True ,
201+ segmentation_key : Optional [str ] = None ,
190202) -> None :
191203 """Write segmentation results to .mod file with imod point annotations.
192204
@@ -201,6 +213,7 @@ def write_segmentation_to_imod_as_points(
201213 estimate_radius_2d: If true the distance to boundary for determining the centroid and computing
202214 the radius will be computed only in 2d rather than in 3d. This can lead to better results
203215 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.
204217 """
205218
206219 # Read the resolution information from the mrcfile.
@@ -212,7 +225,7 @@ def write_segmentation_to_imod_as_points(
212225
213226 # Extract the center coordinates and radii from the segmentation.
214227 if isinstance (segmentation , str ):
215- segmentation = imageio . imread (segmentation )
228+ segmentation = _load_segmentation (segmentation , segmentation_key )
216229 coordinates , radii = convert_segmentation_to_spheres (
217230 segmentation , resolution = resolution , radius_factor = radius_factor , estimate_radius_2d = estimate_radius_2d
218231 )
@@ -221,16 +234,22 @@ def write_segmentation_to_imod_as_points(
221234 write_points_to_imod (coordinates , radii , segmentation .shape , min_radius , output_path )
222235
223236
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" )):
226238 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 ,)
228243
229244 if os .path .isfile (input_path ):
230245 input_files = [input_path ]
231246 input_root = None
232247 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+ )
234253 input_root = input_path
235254
236255 return input_files , input_root
@@ -242,6 +261,7 @@ def export_helper(
242261 output_root : str ,
243262 export_function : callable ,
244263 force : bool = False ,
264+ segmentation_key : Optional [str ] = None ,
245265) -> None :
246266 """
247267 Helper function to run imod export for files in a directory.
@@ -258,9 +278,10 @@ def export_helper(
258278 the path to the segmentation in a .tif file and the output path as only arguments.
259279 If you want to pass additional arguments to this function the use 'funtools.partial'
260280 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.
261282 """
262283 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" )
264285 assert len (input_files ) == len (segmentation_files )
265286
266287 for input_path , seg_path in tqdm (zip (input_files , segmentation_files ), total = len (input_files )):
@@ -279,4 +300,4 @@ def export_helper(
279300 continue
280301
281302 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