Skip to content

Data input and output

Dealing with volumetric data can be done by qim3d for the most common image formats available.

Currently, it is possible to directly load tiff, h5, nii,txm, vol and common PIL formats using one single function.

qim3d.io

qim3d.io.Downloader

Class for downloading large data files available on the QIM data repository.

Attributes:

Name Type Description
folder_name str

Folder class with the name of the folder in https://data.qim.dk/

Syntax for downloading and loading a file is qim3d.io.Downloader().{folder_name}.{file_name}(load_file=True)

Overview of available data

Below is a table of the available folders and files on the QIM data repository.

Folder name File name File size
Coal CoalBrikett
CoalBrikett_Zoom
CoalBrikettZoom_DOWNSAMPLED
2.23 GB
3.72 GB
238 MB
Corals Coral_1
Coral_2
Coral2_DOWNSAMPLED
MexCoral
2.26 GB
2.38 GB
162 MB
2.23 GB
Cowry_Shell Cowry_Shell
Cowry_DOWNSAMPLED
1.82 GB
116 MB
Crab HerrmitCrab
OkinawaCrab
2.38 GB
1.86 GB
Deer_Mandible Animal_Mandible
DeerMandible_DOWNSAMPLED
2.79 GB
638 MB
Foam Foam
Foam_DOWNSAMPLED
Foam_2
Foam_2_zoom
3.72 GB
238 MB
3.72 GB
3.72 GB
Hourglass Hourglass
Hourglass_4X_80kV_Air_9s_1_97um
Hourglass_longexp_rerun
3.72 GB
1.83 GB
3.72 GB
Kiwi Kiwi 2.86 GB
Loofah Loofah
Loofah_DOWNSAMPLED
2.23 GB
143 MB
Marine_Gastropods MarineGatropod_1
MarineGastropod1_DOWNSAMPLED
MarineGatropod_2
MarineGastropod2_DOWNSAMPLED
2.23 GB
143 MB
2.60 GB
166 MB
Mussel ClosedMussel1
ClosedMussel1_DOWNSAMPLED
2.23 GB
143 MB
Oak_Branch Oak_branch
OakBranch_DOWNSAMPLED
2.38 GB
152 MB
Okinawa_Forams Okinawa_Foram_1
Okinawa_Foram_2
1.84 GB
1.84 GB
Physalis Physalis
Physalis_DOWNSAMPLED
3.72 GB
238 MB
Raspberry Raspberry2
Raspberry2_DOWNSAMPLED
2.97 GB
190 MB
Rope FibreRope1
FibreRope1_DOWNSAMPLED
1.82 GB
686 MB
Sea_Urchin SeaUrchin
Cordatum_Shell
Cordatum_Spine
2.60 GB
1.85 GB
183 MB
Snail Escargot 2.60 GB
Sponge Sponge 1.11 GB
Example

import qim3d

downloader = qim3d.io.Downloader()
data = downloader.Cowry_Shell.Cowry_DOWNSAMPLED(load_file=True)

qim3d.viz.orthogonal(data, cmap = "magma")
cowry shell

Source code in qim3d/io/downloader.py
class Downloader:
    """Class for downloading large data files available on the [QIM data repository](https://data.qim.dk/).

    Attributes:
        folder_name (str): Folder class with the name of the folder in <https://data.qim.dk/>

    Syntax for downloading and loading a file is `qim3d.io.Downloader().{folder_name}.{file_name}(load_file=True)`

    ??? info "Overview of available data"
        Below is a table of the available folders and files on the [QIM data repository](https://data.qim.dk/).

        Folder name         | File name                                                                                                          | File size
        ------------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------
        `Coal`              | `CoalBrikett` <br> `CoalBrikett_Zoom` <br> `CoalBrikettZoom_DOWNSAMPLED`                                           | 2.23 GB <br> 3.72 GB <br> 238 MB
        `Corals`            | `Coral_1` <br> `Coral_2` <br> `Coral2_DOWNSAMPLED` <br> `MexCoral`                                                 | 2.26 GB <br> 2.38 GB <br> 162 MB <br> 2.23 GB
        `Cowry_Shell`       | `Cowry_Shell` <br> `Cowry_DOWNSAMPLED`                                                                             | 1.82 GB <br> 116 MB
        `Crab`              | `HerrmitCrab` <br> `OkinawaCrab`                                                                                   | 2.38 GB <br> 1.86 GB
        `Deer_Mandible`     | `Animal_Mandible` <br> `DeerMandible_DOWNSAMPLED` <br>                                                             | 2.79 GB <br> 638 MB
        `Foam`              | `Foam` <br> `Foam_DOWNSAMPLED` <br> `Foam_2` <br> `Foam_2_zoom`                                                    | 3.72 GB <br> 238 MB <br> 3.72 GB <br> 3.72 GB
        `Hourglass`         | `Hourglass` <br> `Hourglass_4X_80kV_Air_9s_1_97um` <br> `Hourglass_longexp_rerun`                                  | 3.72 GB <br> 1.83 GB <br> 3.72 GB
        `Kiwi`              | `Kiwi`                                                                                                             | 2.86 GB
        `Loofah`            | `Loofah` <br> `Loofah_DOWNSAMPLED`                                                                                 | 2.23 GB <br> 143 MB
        `Marine_Gastropods` | `MarineGatropod_1` <br> `MarineGastropod1_DOWNSAMPLED` <br> `MarineGatropod_2` <br> `MarineGastropod2_DOWNSAMPLED` | 2.23 GB <br> 143 MB <br> 2.60 GB <br> 166 MB
        `Mussel`            | `ClosedMussel1` <br> `ClosedMussel1_DOWNSAMPLED`                                                                   | 2.23 GB <br> 143 MB
        `Oak_Branch`        | `Oak_branch` <br> `OakBranch_DOWNSAMPLED`                                                                          | 2.38 GB <br> 152 MB
        `Okinawa_Forams`    | `Okinawa_Foram_1` <br> `Okinawa_Foram_2`                                                                           | 1.84 GB <br> 1.84 GB
        `Physalis`          | `Physalis` <br> `Physalis_DOWNSAMPLED`                                                                             | 3.72 GB <br> 238 MB
        `Raspberry`         | `Raspberry2` <br> `Raspberry2_DOWNSAMPLED`                                                                         | 2.97 GB <br> 190 MB
        `Rope`              | `FibreRope1` <br> `FibreRope1_DOWNSAMPLED`                                                                         | 1.82 GB <br> 686 MB
        `Sea_Urchin`        | `SeaUrchin` <br> `Cordatum_Shell` <br> `Cordatum_Spine`                                                            | 2.60 GB <br> 1.85 GB <br> 183 MB
        `Snail`             | `Escargot`                                                                                                         | 2.60 GB
        `Sponge`            | `Sponge`                                                                                                           | 1.11 GB

    Example:
        ```python
        import qim3d

        downloader = qim3d.io.Downloader()
        data = downloader.Cowry_Shell.Cowry_DOWNSAMPLED(load_file=True)

        qim3d.viz.orthogonal(data, cmap = "magma")
        ```
        ![cowry shell](assets/screenshots/cowry_shell_slicer.gif)
    """

    def __init__(self):
        folders = _extract_names()
        for idx, folder in enumerate(folders):
            exec(f"self.{folder} = self._Myfolder(folder)")

    class _Myfolder:
        """Class for extracting the files from each folder in the Downloader class.

        Args:
            folder(str): name of the folder of interest in the QIM data repository.

        Methods:
             _make_fn(folder,file): creates custom functions for each file found in the folder.
            [file_name_1](load_file,optional): Function to download file number 1 in the given folder.
            [file_name_2](load_file,optional): Function to download file number 2 in the given folder.
            ...
            [file_name_n](load_file,optional): Function to download file number n in the given folder.
        """

        def __init__(self, folder):
            files = _extract_names(folder)

            for idx, file in enumerate(files):
                # Changes names to usable function name.
                file_name = file
                if ("%20" in file) or ("-" in file):
                    file_name = file_name.replace("%20", "_")
                    file_name = file_name.replace("-", "_")

                setattr(self, f'{file_name.split(".")[0]}', self._make_fn(folder, file))

        def _make_fn(self, folder, file):
            """Private method that returns a function. The function downloads the chosen file from the folder.

            Args:
                folder(str): Folder where the file is located.
                file(str): Name of the file to be downloaded.

            Returns:
                    function: the function used to download the file.
            """

            url_dl = "https://archive.compute.dtu.dk/download/public/projects/viscomp_data_repository"

            def _download(load_file=False, virtual_stack=True):
                """Downloads the file and optionally also loads it.

                Args:
                    load_file(bool,optional): Whether to simply download or also load the file.

                Returns:
                    virtual_stack: The loaded image.
                """

                download_file(url_dl, folder, file)
                if load_file == True:
                    log.info(f"\nLoading {file}")
                    file_path = os.path.join(folder, file)

                    return load(path=file_path, virtual_stack=virtual_stack)

            return _download

qim3d.io.load

load(path, virtual_stack=False, dataset_name=None, return_metadata=False, contains=None, progress_bar=True, force_load=False, dim_order=(2, 1, 0), **kwargs)

Load data from the specified file or directory.

Supported formats:

  • Tiff (including file stacks)
  • HDF5
  • TXRM/TXM/XRM
  • NIfTI
  • PIL (including file stacks)
  • VOL/VGI
  • DICOM

Parameters:

Name Type Description Default
path str or PathLike

The path to the file or directory.

required
virtual_stack bool

Specifies whether to use virtual stack when loading files. Default is False.

False
dataset_name str

Specifies the name of the dataset to be loaded in case multiple dataset exist within the same file. Default is None (only for HDF5 files)

None
return_metadata bool

Specifies whether to return metadata or not. Default is False (only for HDF5 and TXRM/TXM/XRM files)

False
contains str

Specifies a part of the name that is common for the TIFF file stack to be loaded (only for TIFF stacks). Default is None.

None
progress_bar bool

Displays tqdm progress bar. Useful for large files. So far works only for linux. Default is False.

True
force_load bool

If the file size exceeds available memory, a MemoryError is raised. If force_load is True, the error is changed to warning and the loader tries to load it anyway. Default is False.

False
dim_order tuple

The order of the dimensions in the volume for .vol files. Default is (2,1,0) which corresponds to (z,y,x)

(2, 1, 0)
**kwargs

Additional keyword arguments to be passed

{}

Returns:

Name Type Description
vol (ndarray, memmap, Dataset, ArrayProxy or tuple)

The loaded volume

If virtual_stack=True, returns numpy.memmap, h5py._hl.dataset.Dataset or nibabel.arrayproxy.ArrayProxy depending on file format If return_metadata=True and file format is either HDF5, NIfTI or TXRM/TXM/XRM, returns tuple (volume, metadata).

Raises:

Type Description
MemoryError

if the given file size exceeds available memory

Example
import qim3d

vol = qim3d.io.load("path/to/image.tif", virtual_stack=True)
Source code in qim3d/io/loading.py
def load(
    path,
    virtual_stack=False,
    dataset_name=None,
    return_metadata=False,
    contains=None,
    progress_bar:bool = True,
    force_load: bool = False,
    dim_order=(2, 1, 0),
    **kwargs,
):
    """
    Load data from the specified file or directory.

    Supported formats:

    - `Tiff` (including file stacks)
    - `HDF5`
    - `TXRM`/`TXM`/`XRM`
    - `NIfTI`
    - `PIL` (including file stacks)
    - `VOL`/`VGI`
    - `DICOM`

    Args:
        path (str or os.PathLike): The path to the file or directory.
        virtual_stack (bool, optional): Specifies whether to use virtual
            stack when loading files. Default is False.
        dataset_name (str, optional): Specifies the name of the dataset to be loaded
            in case multiple dataset exist within the same file. Default is None (only for HDF5 files)
        return_metadata (bool, optional): Specifies whether to return metadata or not. Default is False (only for HDF5 and TXRM/TXM/XRM files)
        contains (str, optional): Specifies a part of the name that is common for the TIFF file stack to be loaded (only for TIFF stacks).
            Default is None.
        progress_bar (bool, optional): Displays tqdm progress bar. Useful for large files. So far works only for linux. Default is False.
        force_load (bool, optional): If the file size exceeds available memory, a MemoryError is raised.
            If force_load is True, the error is changed to warning and the loader tries to load it anyway. Default is False.
        dim_order (tuple, optional): The order of the dimensions in the volume for .vol files. Default is (2,1,0) which corresponds to (z,y,x)
        **kwargs: Additional keyword arguments to be passed
        to the DataLoader constructor.

    Returns:
        vol (numpy.ndarray, numpy.memmap, h5py._hl.dataset.Dataset, nibabel.arrayproxy.ArrayProxy or tuple): The loaded volume

            If `virtual_stack=True`, returns `numpy.memmap`, `h5py._hl.dataset.Dataset` or `nibabel.arrayproxy.ArrayProxy` depending on file format
            If `return_metadata=True` and file format is either HDF5, NIfTI or TXRM/TXM/XRM, returns `tuple` (volume, metadata).

    Raises:
        MemoryError: if the given file size exceeds available memory

    Example:
        ```python
        import qim3d

        vol = qim3d.io.load("path/to/image.tif", virtual_stack=True)
        ```
    """

    loader = DataLoader(
        virtual_stack=virtual_stack,
        dataset_name=dataset_name,
        return_metadata=return_metadata,
        contains=contains,
        force_load=force_load,
        dim_order=dim_order,
        **kwargs,
    )

    if progress_bar and os.name == 'posix':
        with FileLoadingProgressBar(path):
            data = loader.load(path)
    else:
        data = loader.load(path)

    def log_memory_info(data):
        mem = Memory()
        log.info(
            "Volume using %s of memory\n",
            sizeof(data[0].nbytes if isinstance(data, tuple) else data.nbytes),
        )
        mem.report()

    if return_metadata and not isinstance(data, tuple):
        log.warning("The file format does not contain metadata")

    if not virtual_stack:
        log_memory_info(data)
    else:
        # Only log if file type is not a np.ndarray, i.e., it is some kind of memmap object
        if not isinstance(
            type(data[0]) if isinstance(data, tuple) else type(data), np.ndarray
        ):
            log.info("Using virtual stack")
        else:
            log.warning("Virtual stack is not supported for this file format")
            log_memory_info(data)

    return data

qim3d.io.load_mesh

load_mesh(filename)

Load a mesh from an .obj file using trimesh.

Parameters:

Name Type Description Default
filename

The path to the .obj file.

required

Returns:

Name Type Description
mesh

A trimesh object containing the mesh data (vertices and faces).

Example
import qim3d

mesh = qim3d.io.load_mesh("path/to/mesh.obj")
Source code in qim3d/io/loading.py
def load_mesh(filename):
    """
    Load a mesh from an .obj file using trimesh.

    Args:
        filename: The path to the .obj file.

    Returns:
        mesh: A trimesh object containing the mesh data (vertices and faces).

    Example:
        ```python
        import qim3d

        mesh = qim3d.io.load_mesh("path/to/mesh.obj")
        ```
    """
    mesh = trimesh.load(filename)
    return mesh

qim3d.io.save

save(path, data, replace=False, compression=False, basename=None, sliced_dim=0, chunk_shape='auto', **kwargs)

Save data to a specified file path.

Parameters:

Name Type Description Default
path str

The path to save file to. File format is chosen based on the extension. Supported extensions are: '.tif', '.tiff', '.nii', '.nii.gz', '.h5', '.vol', '.vgi', '.dcm', '.DCM', '.zarr', '.jpeg', '.jpg', '.png'

required
data ndarray

The data to be saved

required
replace bool

Specifies if an existing file with identical path should be replaced. Default is False.

False
compression bool

Specifies if the file should be saved with Deflate compression (lossless). Default is False.

False
basename str

Specifies the basename for a TIFF stack saved as several files (only relevant for TIFF stacks). Default is None

None
sliced_dim int

Specifies the dimension that is sliced in case a TIFF stack is saved as several files (only relevant for TIFF stacks). Default is 0, i.e., the first dimension.

0
**kwargs

Additional keyword arguments to be passed to the DataSaver constructor

{}

Raises:

Type Description
ValueError

If the provided path is an existing directory and self.basename is not provided OR If the file format is not supported OR If the provided path does not exist and self.basename is not provided OR If a file extension is not provided OR if a file with the specified path already exists and replace=False.

Example
import qim3d

# Generate synthetic blob
synthetic_blob = qim3d.generate.blob(noise_scale = 0.015)

qim3d.io.save("blob.tif", synthetic_blob, replace=True)

Volumes can also be saved with one file per slice:

import qim3d

# Generate synthetic blob
synthetic_blob = qim3d.generate.blob(noise_scale = 0.015)

qim3d.io.save("slices", synthetic_blob, basename="blob-slices", sliced_dim=0)

Source code in qim3d/io/saving.py
def save(
    path,
    data,
    replace=False,
    compression=False,
    basename=None,
    sliced_dim=0,
    chunk_shape="auto",
    **kwargs,
):
    """Save data to a specified file path.

    Args:
        path (str): The path to save file to. File format is chosen based on the extension. 
            Supported extensions are: <em>'.tif', '.tiff', '.nii', '.nii.gz', '.h5', '.vol', '.vgi', '.dcm', '.DCM', '.zarr', '.jpeg', '.jpg', '.png'</em>
        data (numpy.ndarray): The data to be saved
        replace (bool, optional): Specifies if an existing file with identical path should be replaced.
            Default is False.
        compression (bool, optional): Specifies if the file should be saved with Deflate compression (lossless).
            Default is False.
        basename (str, optional): Specifies the basename for a TIFF stack saved as several files
            (only relevant for TIFF stacks). Default is None
        sliced_dim (int, optional): Specifies the dimension that is sliced in case a TIFF stack is saved
            as several files (only relevant for TIFF stacks). Default is 0, i.e., the first dimension.
        **kwargs: Additional keyword arguments to be passed to the DataSaver constructor

    Raises:
        ValueError: If the provided path is an existing directory and self.basename is not provided <strong>OR</strong>
         If the file format is not supported <strong>OR</strong>
         If the provided path does not exist and self.basename is not provided <strong>OR</strong>
         If a file extension is not provided <strong>OR</strong>
         if a file with the specified path already exists and replace=False.

    Example:
        ```python
        import qim3d

        # Generate synthetic blob
        synthetic_blob = qim3d.generate.blob(noise_scale = 0.015)

        qim3d.io.save("blob.tif", synthetic_blob, replace=True)
        ```

        Volumes can also be saved with one file per slice:
        ```python
        import qim3d

        # Generate synthetic blob
        synthetic_blob = qim3d.generate.blob(noise_scale = 0.015)

        qim3d.io.save("slices", synthetic_blob, basename="blob-slices", sliced_dim=0)
        ```
    """

    DataSaver(
        replace=replace,
        compression=compression,
        basename=basename,
        sliced_dim=sliced_dim,
        chunk_shape=chunk_shape,
        **kwargs,
    ).save(path, data)

qim3d.io.save_mesh

save_mesh(filename, mesh)

Save a trimesh object to an .obj file.

Parameters:

Name Type Description Default
filename

The name of the file to save the mesh.

required
mesh

A trimesh.Trimesh object representing the mesh.

required
Example
import qim3d

vol = qim3d.generate.blob(base_shape=(32, 32, 32),
                          final_shape=(32, 32, 32),
                          noise_scale=0.05,
                          order=1,
                          gamma=1.0,
                          max_value=255,
                          threshold=0.5)
mesh = qim3d.processing.create_mesh(vol)
qim3d.io.save_mesh("mesh.obj", mesh)
Source code in qim3d/io/saving.py
def save_mesh(filename, mesh):
    """
    Save a trimesh object to an .obj file.

    Args:
        filename: The name of the file to save the mesh.
        mesh: A trimesh.Trimesh object representing the mesh.

    Example:
        ```python
        import qim3d

        vol = qim3d.generate.blob(base_shape=(32, 32, 32),
                                  final_shape=(32, 32, 32),
                                  noise_scale=0.05,
                                  order=1,
                                  gamma=1.0,
                                  max_value=255,
                                  threshold=0.5)
        mesh = qim3d.processing.create_mesh(vol)
        qim3d.io.save_mesh("mesh.obj", mesh)
        ```
    """
    # Export the mesh to the specified filename
    mesh.export(filename)

qim3d.io.export_ome_zarr

export_ome_zarr(path, data, chunk_size=256, downsample_rate=2, order=1, replace=False, method='scaleZYX', progress_bar=True, progress_bar_repeat_time='auto')

Export 3D image data to OME-Zarr format with pyramidal downsampling.

This function generates a multi-scale OME-Zarr representation of the input data, which is commonly used for large imaging datasets. The downsampled scales are calculated such that the smallest scale fits within the specified chunk_size.

Parameters:

Name Type Description Default
path str

The directory where the OME-Zarr data will be stored.

required
data ndarray or array

The 3D image data to be exported. Supports both NumPy and Dask arrays.

required
chunk_size int

The size of the chunks for storing data. This affects both the original data and the downsampled scales. Defaults to 256.

256
downsample_rate int

The factor by which to downsample the data for each scale. Must be greater than 1. Defaults to 2.

2
order int

The interpolation order to use when downsampling. Defaults to 1 (linear). Use 0 for a faster nearest-neighbor interpolation.

1
replace bool

Whether to replace the existing directory if it already exists. Defaults to False.

False
method str

The method used for downsampling. If set to "dask", Dask arrays are used for chunking and downsampling. Defaults to "scaleZYX".

'scaleZYX'
progress_bar bool

Whether to display a progress bar during export. Defaults to True.

True
progress_bar_repeat_time str or int

The repeat interval (in seconds) for updating the progress bar. Defaults to "auto".

'auto'

Raises:

Type Description
ValueError

If the directory already exists and replace is False.

ValueError

If downsample_rate is less than or equal to 1.

Example
import qim3d

downloader = qim3d.io.Downloader()
data = downloader.Snail.Escargot(load_file=True)

qim3d.io.export_ome_zarr("Escargot.zarr", data, chunk_size=100, downsample_rate=2)

Returns:

Name Type Description
None

This function writes the OME-Zarr data to the specified directory and does not return any value.

Source code in qim3d/io/ome_zarr.py
def export_ome_zarr(
    path,
    data,
    chunk_size=256,
    downsample_rate=2,
    order=1,
    replace=False,
    method="scaleZYX",
    progress_bar: bool = True,
    progress_bar_repeat_time="auto",
):
    """
    Export 3D image data to OME-Zarr format with pyramidal downsampling.

    This function generates a multi-scale OME-Zarr representation of the input data, which is commonly used for large imaging datasets. The downsampled scales are calculated such that the smallest scale fits within the specified `chunk_size`.

    Args:
        path (str): The directory where the OME-Zarr data will be stored.
        data (np.ndarray or dask.array): The 3D image data to be exported. Supports both NumPy and Dask arrays.
        chunk_size (int, optional): The size of the chunks for storing data. This affects both the original data and the downsampled scales. Defaults to 256.
        downsample_rate (int, optional): The factor by which to downsample the data for each scale. Must be greater than 1. Defaults to 2.
        order (int, optional): The interpolation order to use when downsampling. Defaults to 1 (linear). Use 0 for a faster nearest-neighbor interpolation.
        replace (bool, optional): Whether to replace the existing directory if it already exists. Defaults to False.
        method (str, optional): The method used for downsampling. If set to "dask", Dask arrays are used for chunking and downsampling. Defaults to "scaleZYX".
        progress_bar (bool, optional): Whether to display a progress bar during export. Defaults to True.
        progress_bar_repeat_time (str or int, optional): The repeat interval (in seconds) for updating the progress bar. Defaults to "auto".

    Raises:
        ValueError: If the directory already exists and `replace` is False.
        ValueError: If `downsample_rate` is less than or equal to 1.

    Example:
        ```python
        import qim3d

        downloader = qim3d.io.Downloader()
        data = downloader.Snail.Escargot(load_file=True)

        qim3d.io.export_ome_zarr("Escargot.zarr", data, chunk_size=100, downsample_rate=2)
        ```

    Returns:
        None: This function writes the OME-Zarr data to the specified directory and does not return any value.
    """

    # Check if directory exists
    if os.path.exists(path):
        if replace:
            shutil.rmtree(path)
        else:
            raise ValueError(
                f"Directory {path} already exists. Use replace=True to overwrite."
            )

    # Check if downsample_rate is valid
    if downsample_rate <= 1:
        raise ValueError("Downsample rate must be greater than 1.")

    log.info(f"Exporting data to OME-Zarr format at {path}")

    # Get the number of scales
    min_dim = np.max(np.shape(data))
    nscales = math.ceil(math.log(min_dim / chunk_size) / math.log(downsample_rate))
    log.info(f"Number of scales: {nscales + 1}")

    # Create scaler
    scaler = OMEScaler(
        downscale=downsample_rate, max_layer=nscales, method=method, order=order
    )

    # write the image data
    os.mkdir(path)
    store = parse_url(path, mode="w").store
    root = zarr.group(store=store)

    # Check if we want to process using Dask
    if "dask" in method and not isinstance(data, da.Array):
        log.info("\nConverting input data to Dask array")
        data = da.from_array(data, chunks=(chunk_size, chunk_size, chunk_size))
        log.info(f" - shape...: {data.shape}\n - chunks..: {data.chunksize}\n")

    elif "dask" in method and isinstance(data, da.Array):
        log.info("\nInput data will be rechunked")
        data = data.rechunk((chunk_size, chunk_size, chunk_size))
        log.info(f" - shape...: {data.shape}\n - chunks..: {data.chunksize}\n")


    log.info("Calculating the multi-scale pyramid")

    # Generate multi-scale pyramid
    mip = scaler.func(data)

    log.info("Writing data to disk")
    kwargs = dict(
        pyramid=mip,
        group=root,
        fmt=CurrentFormat(),
        axes="zyx",
        name=None,
        compute=True,
        storage_options=dict(chunks=(chunk_size, chunk_size, chunk_size)),
    )
    if progress_bar:
        n_chunks = get_n_chunks(
            shapes=(scaled_data.shape for scaled_data in mip),
            dtypes=(scaled_data.dtype for scaled_data in mip),
        )
        with OmeZarrExportProgressBar(
            path=path, n_chunks=n_chunks, reapeat_time=progress_bar_repeat_time
        ):
            write_multiscale(**kwargs)
    else:
        write_multiscale(**kwargs)

    log.info("\nAll done!")

    return

qim3d.io.import_ome_zarr

import_ome_zarr(path, scale=0, load=True)

Import image data from an OME-Zarr file.

This function reads OME-Zarr formatted volumetric image data and returns the specified scale. The image data can be lazily loaded (as Dask arrays) or fully computed into memory.

Parameters:

Name Type Description Default
path str

The file path to the OME-Zarr data.

required
scale int or str

The scale level to load. If 'highest', loads the finest scale (scale 0). If 'lowest', loads the coarsest scale (last available scale). Defaults to 0.

0
load bool

Whether to compute the selected scale into memory. If False, returns a lazy Dask array. Defaults to True.

True

Returns:

Type Description

np.ndarray or dask.array.Array: The requested image data, either as a NumPy array if load=True,

or a Dask array if load=False.

Raises:

Type Description
ValueError

If the requested scale does not exist in the data.

Example
import qim3d

data = qim3d.io.import_ome_zarr("Escargot.zarr", scale=0, load=True)
Source code in qim3d/io/ome_zarr.py
def import_ome_zarr(path, scale=0, load=True):
    """
    Import image data from an OME-Zarr file.

    This function reads OME-Zarr formatted volumetric image data and returns the specified scale.
    The image data can be lazily loaded (as Dask arrays) or fully computed into memory.

    Args:
        path (str): The file path to the OME-Zarr data.
        scale (int or str, optional): The scale level to load.
            If 'highest', loads the finest scale (scale 0).
            If 'lowest', loads the coarsest scale (last available scale). Defaults to 0.
        load (bool, optional): Whether to compute the selected scale into memory.
            If False, returns a lazy Dask array. Defaults to True.

    Returns:
        np.ndarray or dask.array.Array: The requested image data, either as a NumPy array if `load=True`,
        or a Dask array if `load=False`.

    Raises:
        ValueError: If the requested `scale` does not exist in the data.

    Example:
        ```python
        import qim3d

        data = qim3d.io.import_ome_zarr("Escargot.zarr", scale=0, load=True)

        ```

    """

    # read the image data
    # store = parse_url(path, mode="r").store

    reader = Reader(parse_url(path))
    nodes = list(reader())
    image_node = nodes[0]
    dask_data = image_node.data

    log.info(f"Data contains {len(dask_data)} scales:")
    for i in np.arange(len(dask_data)):
        log.info(f"- Scale {i}: {dask_data[i].shape}")

    if scale == "highest":
        scale = 0

    if scale == "lowest":
        scale = len(dask_data) - 1

    if scale >= len(dask_data):
        raise ValueError(
            f"Scale {scale} does not exist in the data. Please choose a scale between 0 and {len(dask_data)-1}."
        )

    log.info(f"\nLoading scale {scale} with shape {dask_data[scale].shape}")

    if load:
        vol = dask_data[scale].compute()
    else:
        vol = dask_data[scale]

    return vol