From 03320d866ca8a25e2dc80e51bb05cbe5e5d60d79 Mon Sep 17 00:00:00 2001 From: bmandracchia Date: Mon, 26 Aug 2024 12:38:54 +0200 Subject: [PATCH] movedimg readers moved to io --- bioMONAI/_modidx.py | 28 +- bioMONAI/callbacks.py | 7 + bioMONAI/data.py | 340 ++---------------------- bioMONAI/datasets.py | 4 +- bioMONAI/io.py | 306 ++++++++++++++++++++- bioMONAI/losses.py | 24 +- bioMONAI/metrics.py | 7 + bioMONAI/nets.py | 22 +- bioMONAI/transforms.py | 16 +- bioMONAI/visualize.py | 7 + nbs/01_data.ipynb | 586 +---------------------------------------- nbs/02_io.ipynb | 565 ++++++++++++++++++++++++++++++++++++++- 12 files changed, 955 insertions(+), 957 deletions(-) create mode 100644 bioMONAI/callbacks.py create mode 100644 bioMONAI/metrics.py create mode 100644 bioMONAI/visualize.py diff --git a/bioMONAI/_modidx.py b/bioMONAI/_modidx.py index bba1d0a..5d0775f 100644 --- a/bioMONAI/_modidx.py +++ b/bioMONAI/_modidx.py @@ -5,7 +5,8 @@ 'doc_host': 'https://bmandracchia.github.io', 'git_url': 'https://github.com/bmandracchia/bioMONAI', 'lib_path': 'bioMONAI'}, - 'syms': { 'bioMONAI.core': { 'bioMONAI.core._fig_bounds': ('core.html#_fig_bounds', 'bioMONAI/core.py'), + 'syms': { 'bioMONAI.callbacks': {'bioMONAI.callbacks.foo': ('callbacks.html#foo', 'bioMONAI/callbacks.py')}, + 'bioMONAI.core': { 'bioMONAI.core._fig_bounds': ('core.html#_fig_bounds', 'bioMONAI/core.py'), 'bioMONAI.core.attributesFromDict': ('core.html#attributesfromdict', 'bioMONAI/core.py'), 'bioMONAI.core.get_gt': ('core.html#get_gt', 'bioMONAI/core.py'), 'bioMONAI.core.get_noisy_pair': ('core.html#get_noisy_pair', 'bioMONAI/core.py'), @@ -38,19 +39,18 @@ 'bioMONAI.data.Tensor2BioImage': ('data.html#tensor2bioimage', 'bioMONAI/data.py'), 'bioMONAI.data.Tensor2BioImage.__init__': ('data.html#tensor2bioimage.__init__', 'bioMONAI/data.py'), 'bioMONAI.data.Tensor2BioImage.encodes': ('data.html#tensor2bioimage.encodes', 'bioMONAI/data.py'), - 'bioMONAI.data._image_reader': ('data.html#_image_reader', 'bioMONAI/data.py'), - 'bioMONAI.data._load_and_preprocess': ('data.html#_load_and_preprocess', 'bioMONAI/data.py'), - 'bioMONAI.data._multi_channel': ('data.html#_multi_channel', 'bioMONAI/data.py'), - 'bioMONAI.data._preprocess': ('data.html#_preprocess', 'bioMONAI/data.py'), - 'bioMONAI.data.czi_reader': ('data.html#czi_reader', 'bioMONAI/data.py'), - 'bioMONAI.data.h5_reader': ('data.html#h5_reader', 'bioMONAI/data.py'), - 'bioMONAI.data.img_reader': ('data.html#img_reader', 'bioMONAI/data.py'), - 'bioMONAI.data.lif_reader': ('data.html#lif_reader', 'bioMONAI/data.py'), 'bioMONAI.data.show_batch': ('data.html#show_batch', 'bioMONAI/data.py'), - 'bioMONAI.data.show_results': ('data.html#show_results', 'bioMONAI/data.py'), - 'bioMONAI.data.tiff_reader': ('data.html#tiff_reader', 'bioMONAI/data.py')}, + 'bioMONAI.data.show_results': ('data.html#show_results', 'bioMONAI/data.py')}, 'bioMONAI.datasets': {'bioMONAI.datasets.aics_pipeline': ('datasets.html#aics_pipeline', 'bioMONAI/datasets.py')}, - 'bioMONAI.io': {'bioMONAI.io.foo': ('io.html#foo', 'bioMONAI/io.py')}, + 'bioMONAI.io': { 'bioMONAI.io._image_reader': ('io.html#_image_reader', 'bioMONAI/io.py'), + 'bioMONAI.io._load_and_preprocess': ('io.html#_load_and_preprocess', 'bioMONAI/io.py'), + 'bioMONAI.io._multi_channel': ('io.html#_multi_channel', 'bioMONAI/io.py'), + 'bioMONAI.io._preprocess': ('io.html#_preprocess', 'bioMONAI/io.py'), + 'bioMONAI.io.czi_reader': ('io.html#czi_reader', 'bioMONAI/io.py'), + 'bioMONAI.io.h5_reader': ('io.html#h5_reader', 'bioMONAI/io.py'), + 'bioMONAI.io.img_reader': ('io.html#img_reader', 'bioMONAI/io.py'), + 'bioMONAI.io.lif_reader': ('io.html#lif_reader', 'bioMONAI/io.py'), + 'bioMONAI.io.tiff_reader': ('io.html#tiff_reader', 'bioMONAI/io.py')}, 'bioMONAI.losses': { 'bioMONAI.losses.CombinedLoss': ('losses.html#combinedloss', 'bioMONAI/losses.py'), 'bioMONAI.losses.CombinedLoss.__call__': ('losses.html#combinedloss.__call__', 'bioMONAI/losses.py'), 'bioMONAI.losses.CombinedLoss.__init__': ('losses.html#combinedloss.__init__', 'bioMONAI/losses.py'), @@ -66,6 +66,7 @@ 'bioMONAI.losses.radial_mask': ('losses.html#radial_mask', 'bioMONAI/losses.py'), 'bioMONAI.losses.seventh_fourier_ring_correlation': ( 'losses.html#seventh_fourier_ring_correlation', 'bioMONAI/losses.py')}, + 'bioMONAI.metrics': {'bioMONAI.metrics.foo': ('metrics.html#foo', 'bioMONAI/metrics.py')}, 'bioMONAI.nets': { 'bioMONAI.nets.DnCNN': ('nets.html#dncnn', 'bioMONAI/nets.py'), 'bioMONAI.nets.DnCNN.__init__': ('nets.html#dncnn.__init__', 'bioMONAI/nets.py'), 'bioMONAI.nets.DnCNN.forward': ('nets.html#dncnn.forward', 'bioMONAI/nets.py'), @@ -112,4 +113,5 @@ 'bioMONAI.transforms.RandRot90.encodes': ( 'transforms.html#randrot90.encodes', 'bioMONAI/transforms.py'), 'bioMONAI.transforms._get_sz': ('transforms.html#_get_sz', 'bioMONAI/transforms.py'), - 'bioMONAI.transforms._process_sz': ('transforms.html#_process_sz', 'bioMONAI/transforms.py')}}} + 'bioMONAI.transforms._process_sz': ('transforms.html#_process_sz', 'bioMONAI/transforms.py')}, + 'bioMONAI.visualize': {'bioMONAI.visualize.foo': ('visualize.html#foo', 'bioMONAI/visualize.py')}}} diff --git a/bioMONAI/callbacks.py b/bioMONAI/callbacks.py new file mode 100644 index 0000000..a3d04f9 --- /dev/null +++ b/bioMONAI/callbacks.py @@ -0,0 +1,7 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/07_callbacks.ipynb. + +# %% auto 0 +__all__ = ['foo'] + +# %% ../nbs/07_callbacks.ipynb 3 +def foo(): pass diff --git a/bioMONAI/data.py b/bioMONAI/data.py index 72bab7b..d09779c 100644 --- a/bioMONAI/data.py +++ b/bioMONAI/data.py @@ -1,319 +1,10 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/03_data.ipynb. +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/01_data.ipynb. # %% auto 0 -__all__ = ['tiff_reader', 'lif_reader', 'czi_reader', 'h5_reader', 'img_reader', 'MetaResolver', 'BioImageBase', 'BioImage', - 'BioImageStack', 'BioImageProject', 'BioImageMulti', 'Tensor2BioImage', 'BioImageBlock', 'show_batch', - 'show_results'] +__all__ = ['MetaResolver', 'BioImageBase', 'BioImage', 'BioImageStack', 'BioImageProject', 'BioImageMulti', 'Tensor2BioImage', + 'BioImageBlock', 'show_batch', 'show_results'] -# %% ../nbs/03_data.ipynb 3 -from fastai.vision.all import * -from fastai.data.all import * -from torchio import ScalarImage, ToCanonical, Resample -import multipagetiff as mtif - - -# %% ../nbs/03_data.ipynb 6 -def tiff_reader(path, # The path to the TIFF file to be read - units='um', # The units for the image data. - ): - - """ - Reads a TIFF file and returns the image data along with an identity affine matrix. - - #### Parameters - path (str): The path to the TIFF file to be read. - units (str, optional): The units for the image data. Default is 'um' (micrometers). - - #### Returns - tuple: A tuple containing: - - data (numpy.ndarray): The image data read from the TIFF file as a 4D array (1, Z, Y, X). - - affine (numpy.ndarray): A 4x4 identity affine matrix. - """ - - # Read the TIFF stack using mtif.read_stack with the specified units - stack = mtif.read_stack(path, units=units) - - # Convert the stack pages to a NumPy array of type float32 - data = stack.pages.astype(np.float32) - - # Add a new axis to the data to make it a 4D array (1, Z, Y, X) - data = data[None, :, :, :] - - # Create a 4x4 identity affine matrix - affine = np.eye(4) # to be changed - - # Return the image data and the affine matrix - return data, affine - -# %% ../nbs/03_data.ipynb 11 -from aicsimageio import AICSImage - -def lif_reader(path, # The path to the LIF file to be read - units='um', # The units for the image data. - scene=0, # The scene index to be read from the LIF file - time=0, # The time index to be read from the LIF file - reconstruct_mosaic=False, # Whether to reconstruct a mosaic image from the file - ): - - """ - Reads a LIF (Leica Image File) and returns the image data along with an identity affine matrix. - - Parameters: - path (str): The path to the LIF file to be read. - units (str, optional). - scene (int, optional): The scene index to be read from the LIF file. Default is 0. - time (int, optional): The time index to be read from the LIF file. Default is 0. - reconstruct_mosaic (bool, optional): Whether to reconstruct a mosaic image from the file. Default is False. - - Returns: - tuple: A tuple containing: - - data (numpy.ndarray): The image data read from the LIF file in ZYX format. - - affine (numpy.ndarray): A 4x4 identity affine matrix. - """ - # Create an AICSImage object for the specified file - imagen_aics = AICSImage(path, reconstruct_mosaic=reconstruct_mosaic) - # set scence - - # Retrieve the image data in ZYX format for the specified time point - data = imagen_aics.get_image_data("ZYX", T=time) - - # Create a 4x4 identity affine matrix - affine = np.eye(4) - - # Return the image data and the affine matrix - return data, affine - -# %% ../nbs/03_data.ipynb 14 -from aicsimageio.readers import CziReader - -def czi_reader(path, # The path to the CZI file to be read - ): - - """ - Reads a CZI (Zeiss CZI format) file and returns the image data along with an identity affine matrix. - - Parameters: - path (str): The path to the CZI file to be read. - - Returns: - tuple: A tuple containing: - - data (numpy.ndarray): The image data read from the CZI file. - - affine (numpy.ndarray): A 4x4 identity affine matrix. - """ - - # Create a CziReader for the specified file - reader = CziReader(path) - - # Convert the file to a Numpy Array - data = reader.data - - # Create a 4x4 identity affine NumpyArray - affine = np.eye(4) - - # Return the image data and the affine matrix - return data, affine - -# %% ../nbs/03_data.ipynb 17 -def _image_reader(path, # The file path to the image - ): - - """ - Reads an image from the specified path using AICSImage library. - - Parameters: - path (str): The file path to the image. - - Returns: - tuple: A tuple containing the image data and its affine transformation matrix. - The image data is a NumPy array representing the image. - The affine transformation matrix is a 4x4 NumPy array. - """ - - # Read image using AICSImage library - image_aics = AICSImage(path, reconstruct_mosaic=False) - - # Support for tiff files - path = str(path) - if (path[-4:]=="tiff"): - - # Reorder for tiff files - data = image_aics.get_image_data("CZYX", T=0) # returns 4D CZYX numpy array - - affine = np.eye(4) #to change - - return data, affine - - if (path[-3:]=="tif"): - - # Reorder for tif files - data = image_aics.get_image_data("CZYX", T=0) # returns 4D CZYX numpy array - - affine = np.eye(4) #to change - - return data, affine - - - # Convert to numpy array - data = image_aics.data - - # Remove singleton dimensions - data = np.squeeze(data) - - # Create an identity affine transformation matrix - affine = np.eye(4) - - # Return the image data and the affine matrix - return data, affine - - -# %% ../nbs/03_data.ipynb 20 -import h5py - -def h5_reader(path, dataset): - with h5py.File(path, 'r') as hdf: - ls = list(hdf.keys()) - print('List of datasets in this file: \n',ls) - data = hdf.get(dataset) - dataset1 = np.array(data) - print('Shape of dataset1: \n', dataset1.shape) - - return dataset1 - - -# %% ../nbs/03_data.ipynb 23 -def _preprocess(obj, # The object to preprocess - reorder, # Whether to reorder the object - resample # Whether to resample the object - ): - """ - Preprocesses the given object. - - Args: - obj: The object to preprocess. - reorder: Whether to reorder the object. - resample: Whether to resample the object. - - Returns: - The preprocessed object and its original size. - """ - if reorder: - transform = ToCanonical() - obj = transform(obj) - - - - original_size = obj.shape[1:] - - if resample and not all(np.isclose(obj.spacing, resample)): - transform = Resample(resample) - obj = transform(obj) - - # if MedBase.affine_matrix is None: - # MedBase.affine_matrix = obj.affine - - return obj, original_size - - -# %% ../nbs/03_data.ipynb 25 -def _load_and_preprocess(file_path, # Image file path - reorder=False, # Whether to reorder data for canonical (RAS+) orientation - resample=False, # Whether to resample image to different voxel sizes and dimensions - reader=_image_reader # Whether to resample image to different voxel sizes and dimensions - ): - """ - Helper function to load and preprocess an image. - - Args: - file_path: Image file path. - reorder: Whether to reorder data for canonical (RAS+) orientation. - resample: Whether to resample image to different voxel sizes and dimensions. - dtype: Desired datatype for output. - - Returns: - tuple: Original image, preprocessed image, and its original size. - """ - org_img = ScalarImage(file_path, reader=reader) - input_img, org_size = _preprocess(org_img, reorder, resample) - - return org_img, input_img, org_size - - -# %% ../nbs/03_data.ipynb 28 -def _multi_channel(image_paths: (L, list), # List of image paths (e.g., T1, T2, T1CE, DWI) - reorder: bool = False, # Whether to reorder data for canonical (RAS+) orientation - resample: list = None, # Whether to resample image to different voxel sizes and dimensions - dtype=torch.Tensor, # Desired datatype for output - only_tensor: bool = True, # Whether to return only image tensor - squeeze: bool = False # - ): - """ - Load and preprocess multisequence data. - - Args: - image_paths: List of image paths (e.g., T1, T2, T1CE, DWI). - reorder: Whether to reorder data for canonical (RAS+) orientation. - resample: Whether to resample image to different voxel sizes and dimensions. - dtype: Desired datatype for output. - only_tensor: Whether to return only image tensor. - squeeze: Whether to squeeze or not the image - - Returns: - torch.Tensor: A stacked 4D tensor, if `only_tensor` is True. - tuple: Original image, preprocessed image, original size, if `only_tensor` is False. - """ - image_data = [_load_and_preprocess(image, reorder, resample) for image in image_paths] - org_img, input_img, org_size = image_data[-1] - - tensor = torch.stack([img.data[0] for _, img, _ in image_data], dim=0) - - if only_tensor: - if squeeze: - return torch.squeeze(dtype(tensor)) - return dtype(tensor) - - input_img.set_data(tensor) - return org_img, input_img, org_size - -# %% ../nbs/03_data.ipynb 31 -def img_reader(file_path: (str, Path, L, list), # Path to the image - dtype=torch.Tensor, # Datatype for the return value. Defaults to torch.Tensor - reorder: bool = False, # Whether to reorder to canonical orientation - resample: list = None, # Whether to resample image to different voxel sizes and image dimensions - only_tensor: bool = True, # To return only an image tensor - ): - """Loads and preprocesses a medical image. - - Args: - file_path: Path to the image. Can be a string, Path object or a list. - dtype: Datatype for the return value. Defaults to torch.Tensor. - reorder: Whether to reorder the data to be closest to canonical - (RAS+) orientation. Defaults to False. - resample: Whether to resample image to different voxel sizes and - image dimensions. Defaults to None. - only_tensor: To return only an image tensor. Defaults to True. - - Returns: - The preprocessed image. Returns only the image tensor if - only_tensor is True, otherwise returns original image, - preprocessed image, and original size. - """ - # if isinstance(file_path, str) and ';' in file_path: - # return _multi_channel( - # file_path.split(';'), reorder, resample, dtype, only_tensor) - - if isinstance(file_path, (L, list)): - return _multi_channel(file_path, reorder, resample, dtype, only_tensor) - - org_img, input_img, org_size = _load_and_preprocess( - file_path, reorder, resample) - - if only_tensor: - return dtype(input_img.data.type(torch.float)) - - return org_img, input_img, org_size - - -# %% ../nbs/03_data.ipynb 35 +# %% ../nbs/01_data.ipynb 5 class MetaResolver(type(torch.Tensor), metaclass=BypassNewMeta): """ A class to bypass metaclass conflict: @@ -322,12 +13,13 @@ class MetaResolver(type(torch.Tensor), metaclass=BypassNewMeta): pass -# %% ../nbs/03_data.ipynb 37 -from .core import show_images_grid, mosaic_image_3d +# %% ../nbs/01_data.ipynb 7 +from .core import show_images_grid +from .io import img_reader from monai.data import MetaTensor -# %% ../nbs/03_data.ipynb 38 +# %% ../nbs/01_data.ipynb 8 class BioImageBase(MetaTensor, metaclass=MetaResolver): """ A class that represents an image object. @@ -399,7 +91,7 @@ def __repr__(self) -> str: """Returns the string representation of the ImageBase instance.""" return f"BioImageBase{self.as_tensor().__repr__()[6:]}" -# %% ../nbs/03_data.ipynb 40 +# %% ../nbs/01_data.ipynb 10 class BioImage(BioImageBase): """Subclass of BioImageBase that represents 2D and 3D image objects.""" _show_args = {'cmap':'gray'} @@ -433,7 +125,7 @@ def __repr__(self) -> str: # return f'{self.__class__.__name__} shape={"x".join([str(d) for d in self.shape])}' return f"BioImage{self.as_tensor().__repr__()[6:]}" -# %% ../nbs/03_data.ipynb 43 +# %% ../nbs/01_data.ipynb 13 class BioImageStack(BioImageBase): """Subclass of BioImageBase that represents a 3D image object.""" @@ -441,7 +133,7 @@ def __repr__(self) -> str: """Returns the string representation of the ImageBase instance.""" return f"BioImageStack{self.as_tensor().__repr__()[6:]}" -# %% ../nbs/03_data.ipynb 46 +# %% ../nbs/01_data.ipynb 16 class BioImageProject(BioImageBase): """Subclass of BioImageBase that represents a 2D image object.""" _show_args = {'cmap':'gray'} @@ -475,7 +167,7 @@ def __repr__(self) -> str: """Returns the string representation of the ImageBase instance.""" return f"BioImage{self.as_tensor().__repr__()[6:]}" -# %% ../nbs/03_data.ipynb 49 +# %% ../nbs/01_data.ipynb 19 class BioImageMulti(BioImageBase): """Subclass of BioImageBase that represents a multi-channel 2D image object.""" @@ -504,7 +196,7 @@ def __repr__(self) -> str: return f"BioImageMulti{self.as_tensor().__repr__()[6:]}" -# %% ../nbs/03_data.ipynb 55 +# %% ../nbs/01_data.ipynb 25 class Tensor2BioImage(DisplayedTransform): def __init__(self, cls:BioImageBase=BioImageStack): self.cls = cls @@ -516,12 +208,12 @@ def encodes(self, o): if isinstance(o, torch.Tensor): return self.cls(o) -# %% ../nbs/03_data.ipynb 58 +# %% ../nbs/01_data.ipynb 28 def BioImageBlock(cls:BioImageBase=BioImageStack): "A `TransformBlock` for images of `cls`" return TransformBlock(type_tfms=cls.create, batch_tfms=[Tensor2BioImage(cls)]) # IntToFloatTensor -# %% ../nbs/03_data.ipynb 61 +# %% ../nbs/01_data.ipynb 31 @typedispatch def show_batch(x:BioImageBase, y:BioImageBase, samples, ctxs=None, max_n=10, nrows=None, ncols=None, figsize=None, **kwargs): if ctxs is None: ctxs = get_grid(min(len(samples), max_n), nrows=nrows, ncols=ncols, figsize=figsize, double=True) @@ -529,7 +221,7 @@ def show_batch(x:BioImageBase, y:BioImageBase, samples, ctxs=None, max_n=10, nro ctxs[i::2] = [b.show(ctx=c, **kwargs) for b,c,_ in zip(samples.itemgot(i),ctxs[i::2],range(max_n))] return ctxs -# %% ../nbs/03_data.ipynb 63 +# %% ../nbs/01_data.ipynb 33 @typedispatch def show_results(x:BioImageBase, y:BioImageBase, samples, outs, ctxs=None, max_n=10, figsize=None, **kwargs): if ctxs is None: ctxs = get_grid(3*min(len(samples), max_n), ncols=3, figsize=figsize, title='Input/Target/Prediction') diff --git a/bioMONAI/datasets.py b/bioMONAI/datasets.py index 7ff96da..12926d2 100644 --- a/bioMONAI/datasets.py +++ b/bioMONAI/datasets.py @@ -1,9 +1,9 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/06_datasets.ipynb. +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/08_datasets.ipynb. # %% auto 0 __all__ = ['aics_pipeline'] -# %% ../nbs/06_datasets.ipynb 6 +# %% ../nbs/08_datasets.ipynb 6 def aics_pipeline(n_images_to_download=40, image_save_dir=None): # Set default save directory if not provided if image_save_dir is None: diff --git a/bioMONAI/io.py b/bioMONAI/io.py index f15b187..5d1e10a 100644 --- a/bioMONAI/io.py +++ b/bioMONAI/io.py @@ -1,7 +1,305 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/05_io.ipynb. +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/02_io.ipynb. # %% auto 0 -__all__ = ['foo'] +__all__ = ['tiff_reader', 'lif_reader', 'czi_reader', 'h5_reader', 'img_reader'] + +# %% ../nbs/02_io.ipynb 5 +def tiff_reader(path, # The path to the TIFF file to be read + units='um', # The units for the image data. + ): + + """ + Reads a TIFF file and returns the image data along with an identity affine matrix. + + #### Parameters + path (str): The path to the TIFF file to be read. + units (str, optional): The units for the image data. Default is 'um' (micrometers). + + #### Returns + tuple: A tuple containing: + - data (numpy.ndarray): The image data read from the TIFF file as a 4D array (1, Z, Y, X). + - affine (numpy.ndarray): A 4x4 identity affine matrix. + """ + + # Read the TIFF stack using mtif.read_stack with the specified units + stack = mtif.read_stack(path, units=units) + + # Convert the stack pages to a NumPy array of type float32 + data = stack.pages.astype(np.float32) + + # Add a new axis to the data to make it a 4D array (1, Z, Y, X) + data = data[None, :, :, :] + + # Create a 4x4 identity affine matrix + affine = np.eye(4) # to be changed + + # Return the image data and the affine matrix + return data, affine + +# %% ../nbs/02_io.ipynb 10 +from aicsimageio import AICSImage + +def lif_reader(path, # The path to the LIF file to be read + units='um', # The units for the image data. + scene=0, # The scene index to be read from the LIF file + time=0, # The time index to be read from the LIF file + reconstruct_mosaic=False, # Whether to reconstruct a mosaic image from the file + ): + + """ + Reads a LIF (Leica Image File) and returns the image data along with an identity affine matrix. + + Parameters: + path (str): The path to the LIF file to be read. + units (str, optional). + scene (int, optional): The scene index to be read from the LIF file. Default is 0. + time (int, optional): The time index to be read from the LIF file. Default is 0. + reconstruct_mosaic (bool, optional): Whether to reconstruct a mosaic image from the file. Default is False. + + Returns: + tuple: A tuple containing: + - data (numpy.ndarray): The image data read from the LIF file in ZYX format. + - affine (numpy.ndarray): A 4x4 identity affine matrix. + """ + # Create an AICSImage object for the specified file + imagen_aics = AICSImage(path, reconstruct_mosaic=reconstruct_mosaic) + # set scence + + # Retrieve the image data in ZYX format for the specified time point + data = imagen_aics.get_image_data("ZYX", T=time) + + # Create a 4x4 identity affine matrix + affine = np.eye(4) + + # Return the image data and the affine matrix + return data, affine + +# %% ../nbs/02_io.ipynb 13 +from aicsimageio.readers import CziReader + +def czi_reader(path, # The path to the CZI file to be read + ): + + """ + Reads a CZI (Zeiss CZI format) file and returns the image data along with an identity affine matrix. + + Parameters: + path (str): The path to the CZI file to be read. + + Returns: + tuple: A tuple containing: + - data (numpy.ndarray): The image data read from the CZI file. + - affine (numpy.ndarray): A 4x4 identity affine matrix. + """ + + # Create a CziReader for the specified file + reader = CziReader(path) + + # Convert the file to a Numpy Array + data = reader.data + + # Create a 4x4 identity affine NumpyArray + affine = np.eye(4) + + # Return the image data and the affine matrix + return data, affine + +# %% ../nbs/02_io.ipynb 16 +def _image_reader(path, # The file path to the image + ): + + """ + Reads an image from the specified path using AICSImage library. + + Parameters: + path (str): The file path to the image. + + Returns: + tuple: A tuple containing the image data and its affine transformation matrix. + The image data is a NumPy array representing the image. + The affine transformation matrix is a 4x4 NumPy array. + """ + + # Read image using AICSImage library + image_aics = AICSImage(path, reconstruct_mosaic=False) + + # Support for tiff files + path = str(path) + if (path[-4:]=="tiff"): + + # Reorder for tiff files + data = image_aics.get_image_data("CZYX", T=0) # returns 4D CZYX numpy array + + affine = np.eye(4) #to change + + return data, affine + + if (path[-3:]=="tif"): + + # Reorder for tif files + data = image_aics.get_image_data("CZYX", T=0) # returns 4D CZYX numpy array + + affine = np.eye(4) #to change + + return data, affine + + + # Convert to numpy array + data = image_aics.data + + # Remove singleton dimensions + data = np.squeeze(data) + + # Create an identity affine transformation matrix + affine = np.eye(4) + + # Return the image data and the affine matrix + return data, affine + + +# %% ../nbs/02_io.ipynb 19 +import h5py + +def h5_reader(path, dataset): + with h5py.File(path, 'r') as hdf: + ls = list(hdf.keys()) + print('List of datasets in this file: \n',ls) + data = hdf.get(dataset) + dataset1 = np.array(data) + print('Shape of dataset1: \n', dataset1.shape) + + return dataset1 + + +# %% ../nbs/02_io.ipynb 22 +def _preprocess(obj, # The object to preprocess + reorder, # Whether to reorder the object + resample # Whether to resample the object + ): + """ + Preprocesses the given object. + + Args: + obj: The object to preprocess. + reorder: Whether to reorder the object. + resample: Whether to resample the object. + + Returns: + The preprocessed object and its original size. + """ + if reorder: + transform = ToCanonical() + obj = transform(obj) + + + + original_size = obj.shape[1:] + + if resample and not all(np.isclose(obj.spacing, resample)): + transform = Resample(resample) + obj = transform(obj) + + # if MedBase.affine_matrix is None: + # MedBase.affine_matrix = obj.affine + + return obj, original_size + + +# %% ../nbs/02_io.ipynb 24 +def _load_and_preprocess(file_path, # Image file path + reorder=False, # Whether to reorder data for canonical (RAS+) orientation + resample=False, # Whether to resample image to different voxel sizes and dimensions + reader=_image_reader # Whether to resample image to different voxel sizes and dimensions + ): + """ + Helper function to load and preprocess an image. + + Args: + file_path: Image file path. + reorder: Whether to reorder data for canonical (RAS+) orientation. + resample: Whether to resample image to different voxel sizes and dimensions. + dtype: Desired datatype for output. + + Returns: + tuple: Original image, preprocessed image, and its original size. + """ + org_img = ScalarImage(file_path, reader=reader) + input_img, org_size = _preprocess(org_img, reorder, resample) + + return org_img, input_img, org_size + + +# %% ../nbs/02_io.ipynb 27 +def _multi_channel(image_paths: (L, list), # List of image paths (e.g., T1, T2, T1CE, DWI) + reorder: bool = False, # Whether to reorder data for canonical (RAS+) orientation + resample: list = None, # Whether to resample image to different voxel sizes and dimensions + dtype=torch.Tensor, # Desired datatype for output + only_tensor: bool = True, # Whether to return only image tensor + squeeze: bool = False # + ): + """ + Load and preprocess multisequence data. + + Args: + image_paths: List of image paths (e.g., T1, T2, T1CE, DWI). + reorder: Whether to reorder data for canonical (RAS+) orientation. + resample: Whether to resample image to different voxel sizes and dimensions. + dtype: Desired datatype for output. + only_tensor: Whether to return only image tensor. + squeeze: Whether to squeeze or not the image + + Returns: + torch.Tensor: A stacked 4D tensor, if `only_tensor` is True. + tuple: Original image, preprocessed image, original size, if `only_tensor` is False. + """ + image_data = [_load_and_preprocess(image, reorder, resample) for image in image_paths] + org_img, input_img, org_size = image_data[-1] + + tensor = torch.stack([img.data[0] for _, img, _ in image_data], dim=0) + + if only_tensor: + if squeeze: + return torch.squeeze(dtype(tensor)) + return dtype(tensor) + + input_img.set_data(tensor) + return org_img, input_img, org_size + +# %% ../nbs/02_io.ipynb 30 +def img_reader(file_path: (str, Path, L, list), # Path to the image + dtype=torch.Tensor, # Datatype for the return value. Defaults to torch.Tensor + reorder: bool = False, # Whether to reorder to canonical orientation + resample: list = None, # Whether to resample image to different voxel sizes and image dimensions + only_tensor: bool = True, # To return only an image tensor + ): + """Loads and preprocesses a medical image. + + Args: + file_path: Path to the image. Can be a string, Path object or a list. + dtype: Datatype for the return value. Defaults to torch.Tensor. + reorder: Whether to reorder the data to be closest to canonical + (RAS+) orientation. Defaults to False. + resample: Whether to resample image to different voxel sizes and + image dimensions. Defaults to None. + only_tensor: To return only an image tensor. Defaults to True. + + Returns: + The preprocessed image. Returns only the image tensor if + only_tensor is True, otherwise returns original image, + preprocessed image, and original size. + """ + # if isinstance(file_path, str) and ';' in file_path: + # return _multi_channel( + # file_path.split(';'), reorder, resample, dtype, only_tensor) + + if isinstance(file_path, (L, list)): + return _multi_channel(file_path, reorder, resample, dtype, only_tensor) + + org_img, input_img, org_size = _load_and_preprocess( + file_path, reorder, resample) + + if only_tensor: + return dtype(input_img.data.type(torch.float)) + + return org_img, input_img, org_size -# %% ../nbs/05_io.ipynb 3 -def foo(): pass diff --git a/bioMONAI/losses.py b/bioMONAI/losses.py index 9a8a35e..2b3fb74 100644 --- a/bioMONAI/losses.py +++ b/bioMONAI/losses.py @@ -1,16 +1,16 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/02_losses.ipynb. +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/03_losses.ipynb. # %% auto 0 __all__ = ['SSIMMetric', 'CombinedLoss', 'DiceLoss', 'radial_mask', 'get_radial_masks', 'get_fourier_ring_correlations', 'FRCLoss', 'seventh_fourier_ring_correlation', 'SSIM', 'FRCM'] -# %% ../nbs/02_losses.ipynb 4 +# %% ../nbs/03_losses.ipynb 4 from fastai.vision.all import * -# %% ../nbs/02_losses.ipynb 5 +# %% ../nbs/03_losses.ipynb 5 from monai.losses import SSIMLoss -# %% ../nbs/02_losses.ipynb 8 +# %% ../nbs/03_losses.ipynb 8 class CombinedLoss: "losses combined" def __init__(self, spatial_dims=2, alpha=0.33, beta=0.33): @@ -23,7 +23,7 @@ def __call__(self, pred, targ): return (1 - self.alpha - self.beta) * self.SSIM_loss(pred, targ) + self.alpha * self.MSE_loss(pred, targ) + self.beta * self.MAE_loss(pred, targ) -# %% ../nbs/02_losses.ipynb 10 +# %% ../nbs/03_losses.ipynb 10 class DiceLoss(nn.Module): """ @@ -76,7 +76,7 @@ def forward(self, inputs, targets): return loss -# %% ../nbs/02_losses.ipynb 14 +# %% ../nbs/03_losses.ipynb 14 def radial_mask(r, # Radius of the radial mask cx=128, # X coordinate mask center cy=128, # Y coordinate maske center @@ -113,7 +113,7 @@ def radial_mask(r, # Radius of the radial mask return ind1 * ind2 -# %% ../nbs/02_losses.ipynb 15 +# %% ../nbs/03_losses.ipynb 15 def get_radial_masks(width, height): """ @@ -146,7 +146,7 @@ def get_radial_masks(width, height): return radial_masks, spatial_freq -# %% ../nbs/02_losses.ipynb 17 +# %% ../nbs/03_losses.ipynb 17 def get_fourier_ring_correlations(image1, image2): @@ -217,7 +217,7 @@ def get_fourier_ring_correlations(image1, image2): return FRC , spatial_frequency -# %% ../nbs/02_losses.ipynb 18 +# %% ../nbs/03_losses.ipynb 18 def FRCLoss(image1, image2): """ @@ -234,7 +234,7 @@ def FRCLoss(image1, image2): return (1 - FRCM(image1, image2)) -# %% ../nbs/02_losses.ipynb 19 +# %% ../nbs/03_losses.ipynb 19 from scipy.optimize import curve_fit @@ -272,13 +272,13 @@ def exponential_func(x, a, b, c): return cutoff_frequency -# %% ../nbs/02_losses.ipynb 22 +# %% ../nbs/03_losses.ipynb 22 def SSIM(x, y, spatial_dims=2): return 1 - SSIMLoss(spatial_dims)(x,y) SSIMMetric = AvgMetric(SSIM) -# %% ../nbs/02_losses.ipynb 23 +# %% ../nbs/03_losses.ipynb 23 def FRCM(image1, image2): diff --git a/bioMONAI/metrics.py b/bioMONAI/metrics.py new file mode 100644 index 0000000..d080a8e --- /dev/null +++ b/bioMONAI/metrics.py @@ -0,0 +1,7 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/06_metrics.ipynb. + +# %% auto 0 +__all__ = ['foo'] + +# %% ../nbs/06_metrics.ipynb 3 +def foo(): pass diff --git a/bioMONAI/nets.py b/bioMONAI/nets.py index 722082a..4ea4495 100644 --- a/bioMONAI/nets.py +++ b/bioMONAI/nets.py @@ -1,15 +1,25 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/01_nets.ipynb. +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/04_nets.ipynb. # %% auto 0 __all__ = ['DnCNN', 'SubNetConv', 'UNet'] -# %% ../nbs/01_nets.ipynb 5 +# %% ../nbs/04_nets.ipynb 6 from fastai.vision.all import ConvLayer, Lambda, MaxPool, NormType, nn, np from torch import cat as torch_cat +from torch import Tensor as torch_Tensor import torch.nn.functional as F +import torch.nn as nn +from monai.networks.blocks import Convolution +from monai.networks.layers.factories import Act, Norm, Pool +from monai.networks.nets import resnet +from torchvision.models.resnet import resnet50 #, resnet101 + +from dataclasses import dataclass, field +from typing import List, Tuple, Optional, Union + from .core import attributesFromDict -# %% ../nbs/01_nets.ipynb 7 +# %% ../nbs/04_nets.ipynb 9 class DnCNN(nn.Module): def __init__(self, channels, num_of_layers=9, features=64, kernel_size=3): super(DnCNN, self).__init__() @@ -29,7 +39,7 @@ def forward(self, x): denoised = x - residual return denoised -# %% ../nbs/01_nets.ipynb 11 +# %% ../nbs/04_nets.ipynb 13 def SubNetConv(ks=3, stride=1, padding=None, @@ -60,7 +70,7 @@ def _conv(n_in, n_out, n_conv=1): return _conv -# %% ../nbs/01_nets.ipynb 14 +# %% ../nbs/04_nets.ipynb 16 class _Net_recurse(nn.Module): def __init__(self, depth=4, # depth of the UNet network @@ -121,7 +131,7 @@ def forward(self, x): x_conv_less = self.sub_conv_less(x_cat) return x_conv_less -# %% ../nbs/01_nets.ipynb 16 +# %% ../nbs/04_nets.ipynb 18 class UNet(nn.Module): def __init__(self, depth=4, # depth of the UNet network diff --git a/bioMONAI/transforms.py b/bioMONAI/transforms.py index e4c926f..5b7fbdb 100644 --- a/bioMONAI/transforms.py +++ b/bioMONAI/transforms.py @@ -1,14 +1,14 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/04_transforms.ipynb. +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/05_transforms.ipynb. # %% auto 0 __all__ = ['RandCrop2D', 'RandCropND', 'RandCropND_T', 'RandFlip', 'RandRot90'] -# %% ../nbs/04_transforms.ipynb 3 +# %% ../nbs/05_transforms.ipynb 3 from fastai.vision.all import * from fastai.data.all import * from monai.transforms import SpatialCrop, Flip, Rotate90 -# %% ../nbs/04_transforms.ipynb 7 +# %% ../nbs/05_transforms.ipynb 7 def _process_sz(size, ndim=3): if isinstance(size,int): size=(size,)*ndim @@ -19,7 +19,7 @@ def _get_sz(x): if not isinstance(x, Tensor): return fastuple(x.size) return fastuple(getattr(x, 'img_size', getattr(x, 'sz', (x.shape[1:])))) # maybe it should swap x and y axes -# %% ../nbs/04_transforms.ipynb 11 +# %% ../nbs/05_transforms.ipynb 11 class RandCrop2D(RandTransform): "Randomly crop an image to `size`" split_idx,order = None,1 @@ -49,7 +49,7 @@ def before_call(self, def encodes(self, x): return SpatialCrop(roi_center=self.ctr, roi_size=self.size, lazy=self.lazy)(x) -# %% ../nbs/04_transforms.ipynb 13 +# %% ../nbs/05_transforms.ipynb 13 class RandCropND(RandTransform): """ Randomly crops an ND image to a specified size. @@ -102,7 +102,7 @@ def encodes(self, x): return SpatialCrop(roi_start=self.tl, roi_end=self.br, lazy=self.lazy)(x) -# %% ../nbs/04_transforms.ipynb 16 +# %% ../nbs/05_transforms.ipynb 16 class RandCropND_T(RandTransform): """ Randomly crops an ND image to a specified size. @@ -165,7 +165,7 @@ def encodes(self, x): return cropped_img -# %% ../nbs/04_transforms.ipynb 19 +# %% ../nbs/05_transforms.ipynb 19 class RandFlip(RandTransform): """ Randomly flips an ND image over a specified axis. @@ -198,7 +198,7 @@ def encodes(self, x): else: return x -# %% ../nbs/04_transforms.ipynb 22 +# %% ../nbs/05_transforms.ipynb 22 class RandRot90(RandTransform): """ Randomly rotate an ND image by 90 degrees in the plane specified by axes. diff --git a/bioMONAI/visualize.py b/bioMONAI/visualize.py new file mode 100644 index 0000000..7fa8e9b --- /dev/null +++ b/bioMONAI/visualize.py @@ -0,0 +1,7 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/09_visualize.ipynb. + +# %% auto 0 +__all__ = ['foo'] + +# %% ../nbs/09_visualize.ipynb 3 +def foo(): pass diff --git a/nbs/01_data.ipynb b/nbs/01_data.ipynb index 1edafcb..f379e0b 100644 --- a/nbs/01_data.ipynb +++ b/nbs/01_data.ipynb @@ -28,589 +28,6 @@ "from nbdev.showdoc import *" ] }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "from fastai.vision.all import *\n", - "from fastai.data.all import *\n", - "from torchio import ScalarImage, ToCanonical, Resample\n", - "import multipagetiff as mtif\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Utilities" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Tiff reader" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def tiff_reader(path, # The path to the TIFF file to be read\n", - " units='um', # The units for the image data.\n", - " ):\n", - "\n", - " \"\"\"\n", - " Reads a TIFF file and returns the image data along with an identity affine matrix.\n", - "\n", - " #### Parameters\n", - " path (str): The path to the TIFF file to be read.\n", - " units (str, optional): The units for the image data. Default is 'um' (micrometers).\n", - "\n", - " #### Returns\n", - " tuple: A tuple containing:\n", - " - data (numpy.ndarray): The image data read from the TIFF file as a 4D array (1, Z, Y, X).\n", - " - affine (numpy.ndarray): A 4x4 identity affine matrix.\n", - " \"\"\"\n", - "\n", - " # Read the TIFF stack using mtif.read_stack with the specified units\n", - " stack = mtif.read_stack(path, units=units)\n", - "\n", - " # Convert the stack pages to a NumPy array of type float32\n", - " data = stack.pages.astype(np.float32)\n", - "\n", - " # Add a new axis to the data to make it a 4D array (1, Z, Y, X)\n", - " data = data[None, :, :, :]\n", - "\n", - " # Create a 4x4 identity affine matrix\n", - " affine = np.eye(4) # to be changed\n", - "\n", - " # Return the image data and the affine matrix\n", - " return data, affine" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [], - "source": [ - "# file_path = 'data_examples/example_tiff.tiff's\n", - "\n", - "# d, _ = tiff_reader(file_path)\n", - "\n", - "\n", - "file_path = '../../bioMONAI_0/_data/Thunder_20230308/nuevos_datos/dataset_2/targets/1.tif'\n", - "\n", - "d, _ = tiff_reader(file_path)\n", - "\n", - "file_path = '../../bioMONAI_0/_data/Babesia/TRITC/O11_TRITC_frame01.tiff'\n", - "\n", - "e, _ = tiff_reader(file_path)\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(1, 1, 2048, 2048)" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "d.shape" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(1, 1, 512, 512)" - ] - }, - "execution_count": 56, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "e.shape" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Lif reader" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "from aicsimageio import AICSImage\n", - "\n", - "def lif_reader(path, # The path to the LIF file to be read\n", - " units='um', # The units for the image data.\n", - " scene=0, # The scene index to be read from the LIF file\n", - " time=0, # The time index to be read from the LIF file\n", - " reconstruct_mosaic=False, # Whether to reconstruct a mosaic image from the file\n", - " ):\n", - "\n", - " \"\"\"\n", - " Reads a LIF (Leica Image File) and returns the image data along with an identity affine matrix.\n", - "\n", - " Parameters:\n", - " path (str): The path to the LIF file to be read.\n", - " units (str, optional).\n", - " scene (int, optional): The scene index to be read from the LIF file. Default is 0.\n", - " time (int, optional): The time index to be read from the LIF file. Default is 0.\n", - " reconstruct_mosaic (bool, optional): Whether to reconstruct a mosaic image from the file. Default is False.\n", - "\n", - " Returns:\n", - " tuple: A tuple containing:\n", - " - data (numpy.ndarray): The image data read from the LIF file in ZYX format.\n", - " - affine (numpy.ndarray): A 4x4 identity affine matrix.\n", - " \"\"\"\n", - " # Create an AICSImage object for the specified file\n", - " imagen_aics = AICSImage(path, reconstruct_mosaic=reconstruct_mosaic)\n", - " # set scence\n", - "\n", - " # Retrieve the image data in ZYX format for the specified time point\n", - " data = imagen_aics.get_image_data(\"ZYX\", T=time) \n", - " \n", - " # Create a 4x4 identity affine matrix\n", - " affine = np.eye(4)\n", - "\n", - " # Return the image data and the affine matrix\n", - " return data, affine" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# file_path_2 = 'data_examples/2022-12-05.lif'\n", - "\n", - "# e, _ = lif_reader(file_path_2, units='um')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### CZI reader" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "from aicsimageio.readers import CziReader\n", - "\n", - "def czi_reader(path, # The path to the CZI file to be read\n", - " ):\n", - "\n", - " \"\"\"\n", - " Reads a CZI (Zeiss CZI format) file and returns the image data along with an identity affine matrix.\n", - "\n", - " Parameters:\n", - " path (str): The path to the CZI file to be read.\n", - "\n", - " Returns:\n", - " tuple: A tuple containing:\n", - " - data (numpy.ndarray): The image data read from the CZI file.\n", - " - affine (numpy.ndarray): A 4x4 identity affine matrix.\n", - " \"\"\"\n", - "\n", - " # Create a CziReader for the specified file\n", - " reader = CziReader(path)\n", - "\n", - " # Convert the file to a Numpy Array\n", - " data = reader.data \n", - "\n", - " # Create a 4x4 identity affine NumpyArray\n", - " affine = np.eye(4)\n", - "\n", - " # Return the image data and the affine matrix\n", - " return data, affine" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# file_path_3 = 'data_examples/example_czi.czi'\n", - "\n", - "# f, _ = czi_reader(file_path_3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Image Reader" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def _image_reader(path, # The file path to the image \n", - " ):\n", - "\n", - " \"\"\"\n", - " Reads an image from the specified path using AICSImage library.\n", - "\n", - " Parameters:\n", - " path (str): The file path to the image.\n", - "\n", - " Returns:\n", - " tuple: A tuple containing the image data and its affine transformation matrix.\n", - " The image data is a NumPy array representing the image.\n", - " The affine transformation matrix is a 4x4 NumPy array.\n", - " \"\"\"\n", - "\n", - " # Read image using AICSImage library\n", - " image_aics = AICSImage(path, reconstruct_mosaic=False)\n", - " \n", - " # Support for tiff files \n", - " path = str(path)\n", - " if (path[-4:]==\"tiff\"):\n", - "\n", - " # Reorder for tiff files\n", - " data = image_aics.get_image_data(\"CZYX\", T=0) # returns 4D CZYX numpy array\n", - " \n", - " affine = np.eye(4) #to change\n", - " \n", - " return data, affine\n", - "\n", - " if (path[-3:]==\"tif\"):\n", - "\n", - " # Reorder for tif files\n", - " data = image_aics.get_image_data(\"CZYX\", T=0) # returns 4D CZYX numpy array\n", - " \n", - " affine = np.eye(4) #to change\n", - " \n", - " return data, affine\n", - " \n", - "\n", - " # Convert to numpy array \n", - " data = image_aics.data\n", - "\n", - " # Remove singleton dimensions\n", - " data = np.squeeze(data)\n", - " \n", - " # Create an identity affine transformation matrix\n", - " affine = np.eye(4)\n", - "\n", - " # Return the image data and the affine matrix\n", - " return data, affine\n" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [], - "source": [ - "# file_path = 'data_examples/example_tiff.tiff'\n", - "\n", - "# f, _ = _image_reader(file_path)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### H5 Reader" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "import h5py\n", - "\n", - "def h5_reader(path, dataset):\n", - " with h5py.File(path, 'r') as hdf:\n", - " ls = list(hdf.keys())\n", - " print('List of datasets in this file: \\n',ls)\n", - " data = hdf.get(dataset)\n", - " dataset1 = np.array(data)\n", - " print('Shape of dataset1: \\n', dataset1.shape)\n", - "\n", - " return dataset1\n" - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "metadata": {}, - "outputs": [], - "source": [ - "# f = h5_reader('data_examples/hdf5_data.h5','dataset1')\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Preprocessing" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def _preprocess(obj, # The object to preprocess\n", - " reorder, # Whether to reorder the object\n", - " resample # Whether to resample the object\n", - " ):\n", - " \"\"\"\n", - " Preprocesses the given object.\n", - "\n", - " Args:\n", - " obj: The object to preprocess.\n", - " reorder: Whether to reorder the object.\n", - " resample: Whether to resample the object.\n", - "\n", - " Returns:\n", - " The preprocessed object and its original size.\n", - " \"\"\"\n", - " if reorder:\n", - " transform = ToCanonical()\n", - " obj = transform(obj)\n", - " \n", - "\n", - "\n", - " original_size = obj.shape[1:]\n", - "\n", - " if resample and not all(np.isclose(obj.spacing, resample)):\n", - " transform = Resample(resample)\n", - " obj = transform(obj)\n", - "\n", - " # if MedBase.affine_matrix is None:\n", - " # MedBase.affine_matrix = obj.affine\n", - "\n", - " return obj, original_size\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Load and preprocess" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def _load_and_preprocess(file_path, # Image file path\n", - " reorder=False, # Whether to reorder data for canonical (RAS+) orientation\n", - " resample=False, # Whether to resample image to different voxel sizes and dimensions\n", - " reader=_image_reader # Whether to resample image to different voxel sizes and dimensions\n", - " ):\n", - " \"\"\"\n", - " Helper function to load and preprocess an image.\n", - "\n", - " Args:\n", - " file_path: Image file path.\n", - " reorder: Whether to reorder data for canonical (RAS+) orientation.\n", - " resample: Whether to resample image to different voxel sizes and dimensions.\n", - " dtype: Desired datatype for output.\n", - "\n", - " Returns:\n", - " tuple: Original image, preprocessed image, and its original size.\n", - " \"\"\"\n", - " org_img = ScalarImage(file_path, reader=reader)\n", - " input_img, org_size = _preprocess(org_img, reorder, resample)\n", - " \n", - " return org_img, input_img, org_size\n" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [], - "source": [ - "# load and process any file\n", - "# org_img, input_img, org_size = _load_and_preprocess(file_path)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Read multichannel data" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def _multi_channel(image_paths: (L, list), # List of image paths (e.g., T1, T2, T1CE, DWI)\n", - " reorder: bool = False, # Whether to reorder data for canonical (RAS+) orientation\n", - " resample: list = None, # Whether to resample image to different voxel sizes and dimensions\n", - " dtype=torch.Tensor, # Desired datatype for output\n", - " only_tensor: bool = True, # Whether to return only image tensor\n", - " squeeze: bool = False # \n", - " ):\n", - " \"\"\"\n", - " Load and preprocess multisequence data.\n", - "\n", - " Args:\n", - " image_paths: List of image paths (e.g., T1, T2, T1CE, DWI).\n", - " reorder: Whether to reorder data for canonical (RAS+) orientation.\n", - " resample: Whether to resample image to different voxel sizes and dimensions.\n", - " dtype: Desired datatype for output.\n", - " only_tensor: Whether to return only image tensor.\n", - " squeeze: Whether to squeeze or not the image\n", - "\n", - " Returns:\n", - " torch.Tensor: A stacked 4D tensor, if `only_tensor` is True.\n", - " tuple: Original image, preprocessed image, original size, if `only_tensor` is False.\n", - " \"\"\"\n", - " image_data = [_load_and_preprocess(image, reorder, resample) for image in image_paths]\n", - " org_img, input_img, org_size = image_data[-1]\n", - "\n", - " tensor = torch.stack([img.data[0] for _, img, _ in image_data], dim=0)\n", - "\n", - " if only_tensor: \n", - " if squeeze:\n", - " return torch.squeeze(dtype(tensor))\n", - " return dtype(tensor) \n", - "\n", - " input_img.set_data(tensor)\n", - " return org_img, input_img, org_size" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [], - "source": [ - "# file_names = get_image_files('data_examples')\n", - "\n", - "# _multi_channel(file_names);\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Image reader" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def img_reader(file_path: (str, Path, L, list), # Path to the image\n", - " dtype=torch.Tensor, # Datatype for the return value. Defaults to torch.Tensor\n", - " reorder: bool = False, # Whether to reorder to canonical orientation\n", - " resample: list = None, # Whether to resample image to different voxel sizes and image dimensions\n", - " only_tensor: bool = True, # To return only an image tensor\n", - " ):\n", - " \"\"\"Loads and preprocesses a medical image.\n", - "\n", - " Args:\n", - " file_path: Path to the image. Can be a string, Path object or a list.\n", - " dtype: Datatype for the return value. Defaults to torch.Tensor.\n", - " reorder: Whether to reorder the data to be closest to canonical \n", - " (RAS+) orientation. Defaults to False.\n", - " resample: Whether to resample image to different voxel sizes and \n", - " image dimensions. Defaults to None.\n", - " only_tensor: To return only an image tensor. Defaults to True.\n", - "\n", - " Returns:\n", - " The preprocessed image. Returns only the image tensor if \n", - " only_tensor is True, otherwise returns original image, \n", - " preprocessed image, and original size.\n", - " \"\"\"\n", - " # if isinstance(file_path, str) and ';' in file_path:\n", - " # return _multi_channel(\n", - " # file_path.split(';'), reorder, resample, dtype, only_tensor)\n", - " \n", - " if isinstance(file_path, (L, list)):\n", - " return _multi_channel(file_path, reorder, resample, dtype, only_tensor)\n", - "\n", - " org_img, input_img, org_size = _load_and_preprocess(\n", - " file_path, reorder, resample)\n", - "\n", - " if only_tensor:\n", - " return dtype(input_img.data.type(torch.float))\n", - "\n", - " return org_img, input_img, org_size\n" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": {}, - "outputs": [], - "source": [ - "#img_reader(file_path_2)" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -657,7 +74,8 @@ "source": [ "#| export\n", "\n", - "from bioMONAI.core import show_images_grid, mosaic_image_3d\n", + "from bioMONAI.core import show_images_grid\n", + "from bioMONAI.io import img_reader\n", "from monai.data import MetaTensor\n" ] }, diff --git a/nbs/02_io.ipynb b/nbs/02_io.ipynb index 226cdaa..381215f 100644 --- a/nbs/02_io.ipynb +++ b/nbs/02_io.ipynb @@ -20,7 +20,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -28,19 +28,576 @@ "from nbdev.showdoc import *" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Image Readers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tiff reader" + ] + }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#| export\n", - "def foo(): pass" + "\n", + "def tiff_reader(path, # The path to the TIFF file to be read\n", + " units='um', # The units for the image data.\n", + " ):\n", + "\n", + " \"\"\"\n", + " Reads a TIFF file and returns the image data along with an identity affine matrix.\n", + "\n", + " #### Parameters\n", + " path (str): The path to the TIFF file to be read.\n", + " units (str, optional): The units for the image data. Default is 'um' (micrometers).\n", + "\n", + " #### Returns\n", + " tuple: A tuple containing:\n", + " - data (numpy.ndarray): The image data read from the TIFF file as a 4D array (1, Z, Y, X).\n", + " - affine (numpy.ndarray): A 4x4 identity affine matrix.\n", + " \"\"\"\n", + "\n", + " # Read the TIFF stack using mtif.read_stack with the specified units\n", + " stack = mtif.read_stack(path, units=units)\n", + "\n", + " # Convert the stack pages to a NumPy array of type float32\n", + " data = stack.pages.astype(np.float32)\n", + "\n", + " # Add a new axis to the data to make it a 4D array (1, Z, Y, X)\n", + " data = data[None, :, :, :]\n", + "\n", + " # Create a 4x4 identity affine matrix\n", + " affine = np.eye(4) # to be changed\n", + "\n", + " # Return the image data and the affine matrix\n", + " return data, affine" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# file_path = 'data_examples/example_tiff.tiff's\n", + "\n", + "# d, _ = tiff_reader(file_path)\n", + "\n", + "\n", + "file_path = '../../bioMONAI_0/_data/Thunder_20230308/nuevos_datos/dataset_2/targets/1.tif'\n", + "\n", + "d, _ = tiff_reader(file_path)\n", + "\n", + "file_path = '../../bioMONAI_0/_data/Babesia/TRITC/O11_TRITC_frame01.tiff'\n", + "\n", + "e, _ = tiff_reader(file_path)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1, 1, 2048, 2048)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "d.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1, 1, 512, 512)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "e.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lif reader" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "from aicsimageio import AICSImage\n", + "\n", + "def lif_reader(path, # The path to the LIF file to be read\n", + " units='um', # The units for the image data.\n", + " scene=0, # The scene index to be read from the LIF file\n", + " time=0, # The time index to be read from the LIF file\n", + " reconstruct_mosaic=False, # Whether to reconstruct a mosaic image from the file\n", + " ):\n", + "\n", + " \"\"\"\n", + " Reads a LIF (Leica Image File) and returns the image data along with an identity affine matrix.\n", + "\n", + " Parameters:\n", + " path (str): The path to the LIF file to be read.\n", + " units (str, optional).\n", + " scene (int, optional): The scene index to be read from the LIF file. Default is 0.\n", + " time (int, optional): The time index to be read from the LIF file. Default is 0.\n", + " reconstruct_mosaic (bool, optional): Whether to reconstruct a mosaic image from the file. Default is False.\n", + "\n", + " Returns:\n", + " tuple: A tuple containing:\n", + " - data (numpy.ndarray): The image data read from the LIF file in ZYX format.\n", + " - affine (numpy.ndarray): A 4x4 identity affine matrix.\n", + " \"\"\"\n", + " # Create an AICSImage object for the specified file\n", + " imagen_aics = AICSImage(path, reconstruct_mosaic=reconstruct_mosaic)\n", + " # set scence\n", + "\n", + " # Retrieve the image data in ZYX format for the specified time point\n", + " data = imagen_aics.get_image_data(\"ZYX\", T=time) \n", + " \n", + " # Create a 4x4 identity affine matrix\n", + " affine = np.eye(4)\n", + "\n", + " # Return the image data and the affine matrix\n", + " return data, affine" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# file_path_2 = 'data_examples/2022-12-05.lif'\n", + "\n", + "# e, _ = lif_reader(file_path_2, units='um')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### CZI reader" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "from aicsimageio.readers import CziReader\n", + "\n", + "def czi_reader(path, # The path to the CZI file to be read\n", + " ):\n", + "\n", + " \"\"\"\n", + " Reads a CZI (Zeiss CZI format) file and returns the image data along with an identity affine matrix.\n", + "\n", + " Parameters:\n", + " path (str): The path to the CZI file to be read.\n", + "\n", + " Returns:\n", + " tuple: A tuple containing:\n", + " - data (numpy.ndarray): The image data read from the CZI file.\n", + " - affine (numpy.ndarray): A 4x4 identity affine matrix.\n", + " \"\"\"\n", + "\n", + " # Create a CziReader for the specified file\n", + " reader = CziReader(path)\n", + "\n", + " # Convert the file to a Numpy Array\n", + " data = reader.data \n", + "\n", + " # Create a 4x4 identity affine NumpyArray\n", + " affine = np.eye(4)\n", + "\n", + " # Return the image data and the affine matrix\n", + " return data, affine" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# file_path_3 = 'data_examples/example_czi.czi'\n", + "\n", + "# f, _ = czi_reader(file_path_3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Image Reader" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def _image_reader(path, # The file path to the image \n", + " ):\n", + "\n", + " \"\"\"\n", + " Reads an image from the specified path using AICSImage library.\n", + "\n", + " Parameters:\n", + " path (str): The file path to the image.\n", + "\n", + " Returns:\n", + " tuple: A tuple containing the image data and its affine transformation matrix.\n", + " The image data is a NumPy array representing the image.\n", + " The affine transformation matrix is a 4x4 NumPy array.\n", + " \"\"\"\n", + "\n", + " # Read image using AICSImage library\n", + " image_aics = AICSImage(path, reconstruct_mosaic=False)\n", + " \n", + " # Support for tiff files \n", + " path = str(path)\n", + " if (path[-4:]==\"tiff\"):\n", + "\n", + " # Reorder for tiff files\n", + " data = image_aics.get_image_data(\"CZYX\", T=0) # returns 4D CZYX numpy array\n", + " \n", + " affine = np.eye(4) #to change\n", + " \n", + " return data, affine\n", + "\n", + " if (path[-3:]==\"tif\"):\n", + "\n", + " # Reorder for tif files\n", + " data = image_aics.get_image_data(\"CZYX\", T=0) # returns 4D CZYX numpy array\n", + " \n", + " affine = np.eye(4) #to change\n", + " \n", + " return data, affine\n", + " \n", + "\n", + " # Convert to numpy array \n", + " data = image_aics.data\n", + "\n", + " # Remove singleton dimensions\n", + " data = np.squeeze(data)\n", + " \n", + " # Create an identity affine transformation matrix\n", + " affine = np.eye(4)\n", + "\n", + " # Return the image data and the affine matrix\n", + " return data, affine\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# file_path = 'data_examples/example_tiff.tiff'\n", + "\n", + "# f, _ = _image_reader(file_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### H5 Reader" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "import h5py\n", + "\n", + "def h5_reader(path, dataset):\n", + " with h5py.File(path, 'r') as hdf:\n", + " ls = list(hdf.keys())\n", + " print('List of datasets in this file: \\n',ls)\n", + " data = hdf.get(dataset)\n", + " dataset1 = np.array(data)\n", + " print('Shape of dataset1: \\n', dataset1.shape)\n", + "\n", + " return dataset1\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# f = h5_reader('data_examples/hdf5_data.h5','dataset1')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Preprocessing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def _preprocess(obj, # The object to preprocess\n", + " reorder, # Whether to reorder the object\n", + " resample # Whether to resample the object\n", + " ):\n", + " \"\"\"\n", + " Preprocesses the given object.\n", + "\n", + " Args:\n", + " obj: The object to preprocess.\n", + " reorder: Whether to reorder the object.\n", + " resample: Whether to resample the object.\n", + "\n", + " Returns:\n", + " The preprocessed object and its original size.\n", + " \"\"\"\n", + " if reorder:\n", + " transform = ToCanonical()\n", + " obj = transform(obj)\n", + " \n", + "\n", + "\n", + " original_size = obj.shape[1:]\n", + "\n", + " if resample and not all(np.isclose(obj.spacing, resample)):\n", + " transform = Resample(resample)\n", + " obj = transform(obj)\n", + "\n", + " # if MedBase.affine_matrix is None:\n", + " # MedBase.affine_matrix = obj.affine\n", + "\n", + " return obj, original_size\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load and preprocess" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def _load_and_preprocess(file_path, # Image file path\n", + " reorder=False, # Whether to reorder data for canonical (RAS+) orientation\n", + " resample=False, # Whether to resample image to different voxel sizes and dimensions\n", + " reader=_image_reader # Whether to resample image to different voxel sizes and dimensions\n", + " ):\n", + " \"\"\"\n", + " Helper function to load and preprocess an image.\n", + "\n", + " Args:\n", + " file_path: Image file path.\n", + " reorder: Whether to reorder data for canonical (RAS+) orientation.\n", + " resample: Whether to resample image to different voxel sizes and dimensions.\n", + " dtype: Desired datatype for output.\n", + "\n", + " Returns:\n", + " tuple: Original image, preprocessed image, and its original size.\n", + " \"\"\"\n", + " org_img = ScalarImage(file_path, reader=reader)\n", + " input_img, org_size = _preprocess(org_img, reorder, resample)\n", + " \n", + " return org_img, input_img, org_size\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# load and process any file\n", + "# org_img, input_img, org_size = _load_and_preprocess(file_path)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Read multichannel data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def _multi_channel(image_paths: (L, list), # List of image paths (e.g., T1, T2, T1CE, DWI)\n", + " reorder: bool = False, # Whether to reorder data for canonical (RAS+) orientation\n", + " resample: list = None, # Whether to resample image to different voxel sizes and dimensions\n", + " dtype=torch.Tensor, # Desired datatype for output\n", + " only_tensor: bool = True, # Whether to return only image tensor\n", + " squeeze: bool = False # \n", + " ):\n", + " \"\"\"\n", + " Load and preprocess multisequence data.\n", + "\n", + " Args:\n", + " image_paths: List of image paths (e.g., T1, T2, T1CE, DWI).\n", + " reorder: Whether to reorder data for canonical (RAS+) orientation.\n", + " resample: Whether to resample image to different voxel sizes and dimensions.\n", + " dtype: Desired datatype for output.\n", + " only_tensor: Whether to return only image tensor.\n", + " squeeze: Whether to squeeze or not the image\n", + "\n", + " Returns:\n", + " torch.Tensor: A stacked 4D tensor, if `only_tensor` is True.\n", + " tuple: Original image, preprocessed image, original size, if `only_tensor` is False.\n", + " \"\"\"\n", + " image_data = [_load_and_preprocess(image, reorder, resample) for image in image_paths]\n", + " org_img, input_img, org_size = image_data[-1]\n", + "\n", + " tensor = torch.stack([img.data[0] for _, img, _ in image_data], dim=0)\n", + "\n", + " if only_tensor: \n", + " if squeeze:\n", + " return torch.squeeze(dtype(tensor))\n", + " return dtype(tensor) \n", + "\n", + " input_img.set_data(tensor)\n", + " return org_img, input_img, org_size" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# file_names = get_image_files('data_examples')\n", + "\n", + "# _multi_channel(file_names);\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Image reader" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def img_reader(file_path: (str, Path, L, list), # Path to the image\n", + " dtype=torch.Tensor, # Datatype for the return value. Defaults to torch.Tensor\n", + " reorder: bool = False, # Whether to reorder to canonical orientation\n", + " resample: list = None, # Whether to resample image to different voxel sizes and image dimensions\n", + " only_tensor: bool = True, # To return only an image tensor\n", + " ):\n", + " \"\"\"Loads and preprocesses a medical image.\n", + "\n", + " Args:\n", + " file_path: Path to the image. Can be a string, Path object or a list.\n", + " dtype: Datatype for the return value. Defaults to torch.Tensor.\n", + " reorder: Whether to reorder the data to be closest to canonical \n", + " (RAS+) orientation. Defaults to False.\n", + " resample: Whether to resample image to different voxel sizes and \n", + " image dimensions. Defaults to None.\n", + " only_tensor: To return only an image tensor. Defaults to True.\n", + "\n", + " Returns:\n", + " The preprocessed image. Returns only the image tensor if \n", + " only_tensor is True, otherwise returns original image, \n", + " preprocessed image, and original size.\n", + " \"\"\"\n", + " # if isinstance(file_path, str) and ';' in file_path:\n", + " # return _multi_channel(\n", + " # file_path.split(';'), reorder, resample, dtype, only_tensor)\n", + " \n", + " if isinstance(file_path, (L, list)):\n", + " return _multi_channel(file_path, reorder, resample, dtype, only_tensor)\n", + "\n", + " org_img, input_img, org_size = _load_and_preprocess(\n", + " file_path, reorder, resample)\n", + "\n", + " if only_tensor:\n", + " return dtype(input_img.data.type(torch.float))\n", + "\n", + " return org_img, input_img, org_size\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#img_reader(file_path_2)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, "metadata": {}, "outputs": [], "source": [