Folder Reading and Semantic Merging
The examples below assume the following imports:
import omio as om
import pprint
Imread’s Folder Reading and Merging Capability
imread’s fname argument is not restricted to single file names. You can also provide
a folder name containing multiple image files of the same type (e.g., multiple TIFF files)
or different types (e.g., TIFF, CZI, LSM, RAW). In this case, imread will scan the provided
folder for all supported image files, read them one by one, and returns, by default, a list
of images and a list of metadata dictionaries, one for each read file.
fname_folder = "example_data/tif_dummy_data/tif_folder_with_multiple_files/"
images_folder, metadata_folder = om.imread(fname_folder)
print(f"Number of images read from folder: {len(images_folder)}\n")
for i, (img, meta) in enumerate(zip(images_folder, metadata_folder)):
print(f"Image {i}: shape={img.shape}, axes={meta.get('axes', 'N/A')}")
>>>
Number of images read from folder: 3
Image 0: shape=(1, 10, 2, 20, 100), axes=TZCYX
Image 1: shape=(1, 10, 2, 20, 100), axes=TZCYX
Image 2: shape=(1, 10, 2, 20, 100), axes=TZCYX
Depending on your use case, you may want to merge the read images into a single
multidimensional array along a new axis (e.g., time, channel). To do so, you can set
the merge_multiple_files_in_folder argument to True and specify the desired axis
along which to merge the images via the merge_along_axis argument:
images_merged, metadata_merged = om.imread(
fname_folder,
merge_multiple_files_in_folder=True,
merge_along_axis="T")
print(f"Merged image shape: {images_merged.shape} "
f"with axes {metadata_merged.get('axes', 'N/A')}")
>>>
Merged image shape: (3, 10, 2, 20, 100) with axes TZCYX
In case of unequal image shapes, merging will still work if the optional argument
zeropadding is set to True (which is the default). In this case, smaller images
will be zero-padded to match the largest image shape along each axis before merging:
fname_folder = "example_data/tif_dummy_data/tif_folder_with_multiple_files_unequal_shapes/"
images_merged, metadata_merged = om.imread(
fname_folder,
merge_multiple_files_in_folder=True,
merge_along_axis="T")
print(f"Merged image shape: {images_merged.shape} "
f"with axes {metadata_merged.get('axes', 'N/A')}")
>>>
Merged image shape: (5, 10, 2, 20, 100) with axes TZCYX
In case zeropadding is set to False, imread will not merge the images and returns
None for both image and metadata:
images_merged, metadata_merged = om.imread(
fname_folder,
merge_multiple_files_in_folder=True,
merge_along_axis="T",
zeropadding=False)
print(f"type of merged images: {type(images_merged)},\n"
f"type of merged metadata: {type(metadata_merged)}")
>>>
type of merged images: <class 'NoneType'>,
type of merged metadata: <class 'NoneType'>
Folder Stacks Reading and Merging
OMIO also supports reading of tagged folders or folder stacks, where sub-folders are named according to specific preceding tags. For example:
example_dataset/
├── T0_FOV1...
├── T0_FOV2...
├── T0_FOV3...
├── T1_FOV1...
├── T1_FOV2...
├── HC_FOV1...
├── HC_FOV2...
└── ...
In this example:
T0,T1are tags indicating different time pointsHCis a tag indicating, e.g., hippocampus regionFOV1,FOV2are tags indicating different fields of view
OMIO can read such tagged folders and merge the read images along multiple new axes.
To do so, provide one of the desired tag-folders (T0_FOV1..., …) as fname argument
to imread and set the optional argument folder_stacks to True.
imread will then split fname based on the underscore (_) character and set the
first part as the folder stack tag. It will then scan for all folders in the parent
directory of fname that start with any of the detected tags and read the image files
in each of these folders.
fname_folder_stacks = "example_data/tif_dummy_data/tif_folder_stacks/FOV1_time001"
images_folder_stacks, metadata_folder_stacks = om.imread(
fname_folder_stacks,
folder_stacks=True)
Terminal output during execution:
>>>
folder_stacks=True, merge_folder_stacks=False ⟶ will read from tagged folder stacks.
Detected folder stack tag: 'FOV1_'.
Reading TIFF fully into RAM...
Correcting for OME axes order...
Got NumPy array as input. Will return reordered NumPy array.
Finished reading TIFF.
Reading TIFF fully into RAM...
Correcting for OME axes order...
Got NumPy array as input. Will return reordered NumPy array.
Finished reading TIFF.
print(f"Number of images read from folder stacks: {len(images_folder_stacks)}\n")
for i, (img, meta) in enumerate(zip(images_folder_stacks, metadata_folder_stacks)):
print(f"Image {i}: shape={img.shape}, axes={meta.get('axes', 'N/A')}")
>>>
Number of images read from folder stacks: 2
Image 0: shape=(5, 10, 2, 20, 100), axes=TZCYX
Image 1: shape=(5, 10, 2, 20, 100), axes=TZCYX
In the example above, imread interpreted FOV1 as the folder stack tag and read all
folders starting with, e.g., FOV1 in the parent directory of fname_folder_stacks. Note
that folders starting with, e.g., FOV2 were ignored. imread also ignores any
additional parts in the folder names after the first underscore (_), so that folders
such as FOV1_time002 are also correctly recognized. This gives the user more
flexibility in naming the tagged or stacked folders by, for example, adding imaging
depth or other additional notes.
What are stacked folders good for? They allow merging of the read images along a
specified axis. To do so, set the optional argument merge_folder_stacks to True
and specify the desired axis via merge_along_axis:
images_folder_stacks_merged, metadata_folder_stacks_merged = om.imread(
fname_folder_stacks,
folder_stacks=True,
merge_folder_stacks=True,
merge_along_axis="T")
print(f"Merged image shape from folder stacks: "
f"{images_folder_stacks_merged.shape} "
f"with axes {metadata_folder_stacks_merged.get('axes', 'N/A')}")
>>>
Merged image shape from folder stacks: (10, 10, 2, 20, 100) with axes TZCYX
imconvert also supports reading and merging of tagged folder stacks. It is recommended
to set in this case relative_path to write the converted OME-TIFF file into a sub-folder
of the input folder’s parent directory to avoid overwriting the original
files. Furthermore, we recommend setting the relative path one level up (“../…”),
as otherwise the created sub-folder would be placed into the folder defined in fname:
output_fnames_folder_stacks = om.imconvert(
fname_folder_stacks,
folder_stacks=True,
merge_folder_stacks=True,
merge_along_axis="T",
relative_path="../omio_converted_FOV1",
return_fnames=True)
for ofname in output_fnames_folder_stacks:
print(f"Converted file name from folder stacks: {ofname}")
>>>
Converted file name from folder stacks: ../example_data/tif_dummy_data/tif_folder_stacks/FOV1_time001/../omio_converted_FOV1/TZCYX_T5_Z10_C2_FOV1_time001_merged.ome.tif