Source code for decode.utils.frames_io
import warnings
import torch
import pathlib
import tifffile
from typing import Union, Tuple, Callable, Iterable
from tqdm import tqdm
[docs]def load_tif(path: (str, pathlib.Path), multifile=True) -> torch.Tensor:
"""
Reads the tif(f) files. When a folder is specified, potentially multiple files are loaded.
Which are stacked into a new first axis.
Make sure that if you provide multiple files (i.e. a folder) sorting gives the correct order. Otherwise we can
not guarantee anything.
Args:
path: path to the tiff / or folder
multifile: auto-load multi-file tiff (for large frame stacks). When path is a directory, multifile is
automatically disabled.
Returns:
torch.Tensor: frames
"""
p = pathlib.Path(path)
"""If dir, load multiple files and stack them if more than one found"""
if p.is_dir():
file_list = sorted(p.glob('*.tif*')) # load .tif or .tiff
frames = []
for f in tqdm(file_list, desc="Tiff loading"):
frames.append(torch.from_numpy(tifffile.imread(str(f), multifile=False).astype('float32')))
if frames.__len__() >= 2:
frames = torch.stack(frames, 0)
else:
frames = frames[0]
else:
im = tifffile.imread(str(p), multifile=multifile)
frames = torch.from_numpy(im.astype('float32'))
if frames.squeeze().ndim <= 2:
warnings.warn(f"Frames seem to be of wrong dimension ({frames.size()}), "
f"or could only find a single frame.", ValueError)
return frames
[docs]class TiffTensor:
def __init__(self, file, dtype='float32'):
"""
Memory-mapped tensor. Note that data is loaded only to the extent to which the object is accessed through brackets '[ ]'
Therefore, this tensor has no value and no state until it is sliced and then returns a torch tensor.
You can of course enforce loading the whole tiff by tiff_tensor[:]
Args:
file: path to tiff file
dtype: data type to which to convert
"""
self._file = file
self._dtype = dtype
def __getitem__(self, pos) -> torch.Tensor:
# convert to tuple if not already
if not isinstance(pos, tuple):
pos = tuple([pos])
image = tifffile.imread(str(self._file), key=pos[0]).astype(self._dtype)
if len(pos) == 1:
return torch.from_numpy(image)
return torch.from_numpy(image).__getitem__(pos[1:])
def __setitem(self, key, value):
raise NotImplementedError
def __len__(self):
tiff = tifffile.TiffFile(self._file, mode='rb')
n = len(tiff.pages)
tiff.close()
return n
[docs]class BatchFileLoader:
def __init__(self, par_folder: Union[str, pathlib.Path],
file_suffix: str = '.tif',
file_loader: Union[None, Callable] = None,
exclude_pattern: Union[None, str] = None):
"""
Iterates through parent folder and returns the loaded frames as well as the filename in their iterator
Example:
>>> batch_loader = BatchFileLoader('dummy_folder')
>>> for frame, file in batch_loader:
>>> out = model.forward(frame)
Args:
par_folder: parent folder in which the files are
file_suffix: suffix to search for
exclude_pattern: specifies excluded patterns via regex string. If that pattern is found anywhere (!) in the
files path, the file will be ingored.
"""
self.par_folder = par_folder if isinstance(par_folder, pathlib.Path) else pathlib.Path(par_folder)
if not self.par_folder.is_dir():
raise FileExistsError(f"Path {str(self.par_folder)} is either not a directory or does not exist.")
self.files = list(self.par_folder.rglob('*' + file_suffix))
self.file_loader = file_loader if file_loader is not None else load_tif
self._exclude_pattern = exclude_pattern if isinstance(exclude_pattern, (list, tuple)) else [exclude_pattern]
self.remove_by_exclude()
self._n = -1
def __len__(self) -> int:
return len(self.files)
def __iter__(self):
return self
def __next__(self) -> Tuple[torch.Tensor, pathlib.Path]:
"""
Returns:
torch.Tensor: frames
Path: path to file
"""
if self._n >= len(self) - 1:
raise StopIteration
self._n += 1
return self.file_loader(self.files[self._n]), self.files[self._n]
[docs] def remove_by_exclude(self):
"""
Removes the the files that match the exclude pattern
"""
if self._exclude_pattern is None:
return
assert isinstance(self._exclude_pattern, (list, tuple))
for e in self._exclude_pattern:
excludes = set(self.par_folder.rglob(e))
self.files = list(set(self.files) - excludes)