Loading multi-channel / multi-position folders of tif-files#
Some microscopes write image data to disc as tif-files slice-by slice. You find then many files named for example image_z03_ch01.tif
in these folders. For loading these folders you typically need to know details such as how many z-slices and how many channels were imaged, or if the image data has multiple time-points or not.
See also this discussion.
from skimage import io
import matplotlib.pyplot as plt
import tifffile as tif
import numpy as np
import shutil
import os
path = "../../data/tif_folder/"
For demonstration purposes, we just create such a folder with dummy image data.
if not os.path.exists(path):
os.mkdir(path)
for z in range(1,7):
for c in range(1,5):
#image = io.imread("c:/structure/data/blobs.tif")
#io.imsave(f"c:/structure/data/images/r01c01f34p0{z}-ch0{c}t01.tiff", image)
shutil.copy("../../data/blobs.tif",
path + f"image_z{str(z).zfill(2)}-ch{str(c).zfill(2)}.tiff")
To get an overview, we can print out the file names in the folder.
for file in os.listdir(path):
print(file)
image_z01-ch01.tiff
image_z01-ch02.tiff
image_z01-ch03.tiff
image_z01-ch04.tiff
image_z02-ch01.tiff
image_z02-ch02.tiff
image_z02-ch03.tiff
image_z02-ch04.tiff
image_z03-ch01.tiff
image_z03-ch02.tiff
image_z03-ch03.tiff
image_z03-ch04.tiff
image_z04-ch01.tiff
image_z04-ch02.tiff
image_z04-ch03.tiff
image_z04-ch04.tiff
image_z05-ch01.tiff
image_z05-ch02.tiff
image_z05-ch03.tiff
image_z05-ch04.tiff
image_z06-ch01.tiff
image_z06-ch02.tiff
image_z06-ch03.tiff
image_z06-ch04.tiff
scikit-image offers a imread_collection
for loading files matching to a pattern, e.g. containing *
.
im_collection = io.imread_collection(path + "*")
im_collection
<skimage.io.collection.ImageCollection at 0x2244cd228e0>
You can turn this collection of images into an numpy-array-based image stack. Unfortunately, the number of z-slices and channels is unknown at this point.
image_stack = im_collection.concatenate()
image_stack.shape
(24, 254, 256)
If you know the number of z-slices and channels, you can reshape
the image to a 3D+ch or 4D image.
num_channels = 4
num_z_slices = 6
image4d = np.reshape(image_stack, (num_channels, num_z_slices, image_stack.shape[-2], image_stack.shape[-1]))
image4d.shape
(4, 6, 254, 256)
Alternatively, you can also build your own for-loops for loading the data from disc. This gives you a bit more freedom, e.g. for sorting slices and channels into the dimensions used.
num_channels = 4
num_z_slices = 6
image4d_loaded = np.asarray([
[io.imread(path + f"image_z{str(z).zfill(2)}-ch{str(c).zfill(2)}.tiff") for c in range(1, 5)]
for z in range(1, 7)
])
image4d_loaded.shape
(6, 4, 254, 256)