Skip to content

Input/Output

All the input/output operations are handled by the plantseg.io module. This module provides functions to read and write data in different formats. The supported formats are tiff, h5, and zarr, jpeg, png.

Reading

plantseg.io.smart_load(path: Path, key: str | None = None, default=load_tiff) -> np.ndarray

Load a dataset from a file. The loader is chosen based on the file extension. Supported formats are: tiff, h5, zarr, and PIL images. If the format is not supported, a default loader can be provided (default: load_tiff).

Parameters:

  • path (Path) –

    path to the file to load.

  • key (str, default: None ) –

    key of the dataset to load (if h5 or zarr).

  • default (callable, default: load_tiff ) –

    default loader if the type is not understood.

Returns:

  • stack ( ndarray ) –

    numpy array with the image data.

Examples:

>>> data = smart_load('path/to/file.tif')
>>> data = smart_load('path/to/file.h5', key='raw')
Source code in plantseg/io/io.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
def smart_load(path: Path, key: str | None = None, default=load_tiff) -> np.ndarray:
    """
    Load a dataset from a file. The loader is chosen based on the file extension.
    Supported formats are: tiff, h5, zarr, and PIL images.
    If the format is not supported, a default loader can be provided (default: load_tiff).

    Args:
        path (Path): path to the file to load.
        key (str): key of the dataset to load (if h5 or zarr).
        default (callable): default loader if the type is not understood.

    Returns:
        stack (np.ndarray): numpy array with the image data.

    Examples:
        >>> data = smart_load('path/to/file.tif')
        >>> data = smart_load('path/to/file.h5', key='raw')

    """
    ext = (path.suffix).lower()
    if key == "":
        key = None

    if ext in H5_EXTENSIONS:
        return load_h5(path, key)

    elif ext in TIFF_EXTENSIONS:
        return load_tiff(path)

    elif ext in PIL_EXTENSIONS:
        return load_pil(path)

    elif ext in ZARR_EXTENSIONS:
        return load_zarr(path, key)

    else:
        logger.warning(f"No default found for {ext}, reverting to default loader.")
        return default(path)

Writing

plantseg.io.create_tiff(path: Path, stack: np.ndarray, voxel_size: VoxelSize, layout: str = 'ZYX') -> None

Create a tiff file from a numpy array

Parameters:

  • path (Path) –

    path to save the tiff file

  • stack (ndarray) –

    numpy array to save as tiff

  • voxel_size (list or tuple) –

    tuple of the voxel size

  • voxel_size_unit (str) –

    units of the voxel size

Source code in plantseg/io/tiff.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
def create_tiff(path: Path, stack: np.ndarray, voxel_size: VoxelSize, layout: str = "ZYX") -> None:
    """
    Create a tiff file from a numpy array

    Args:
        path (Path): path to save the tiff file
        stack (np.ndarray): numpy array to save as tiff
        voxel_size (list or tuple): tuple of the voxel size
        voxel_size_unit (str): units of the voxel size

    """
    # taken from: https://pypi.org/project/tifffile docs
    # dimensions in TZCYXS order
    if layout == "ZYX":
        assert stack.ndim == 3, "Stack dimensions must be in ZYX order"
        z, y, x = stack.shape
        stack = stack.reshape(1, z, 1, y, x, 1)

    elif layout == "YX":
        assert stack.ndim == 2, "Stack dimensions must be in YX order"
        y, x = stack.shape
        stack = stack.reshape(1, 1, 1, y, x, 1)

    elif layout == "CYX":
        assert stack.ndim == 3, "Stack dimensions must be in CYX order"
        c, y, x = stack.shape
        stack = stack.reshape(1, 1, c, y, x, 1)

    elif layout == "ZCYX":
        assert stack.ndim == 4, "Stack dimensions must be in ZCYX order"
        z, c, y, x = stack.shape
        stack = stack.reshape(1, z, c, y, x, 1)

    elif layout == "CZYX":
        assert stack.ndim == 4, "Stack dimensions must be in CZYX order"
        c, z, y, x = stack.shape
        stack = stack.reshape(1, z, c, y, x, 1)

    else:
        raise ValueError(f"Layout {layout} not supported")

    if voxel_size.voxels_size is not None:
        assert len(voxel_size.voxels_size) == 3, "Voxel size must have 3 elements (z, y, x)"
        spacing, y, x = voxel_size.voxels_size
    else:
        spacing, y, x = (1.0, 1.0, 1.0)

    resolution = (1.0 / x, 1.0 / y)
    # Save output results as tiff
    tifffile.imwrite(
        path,
        data=stack,
        dtype=stack.dtype,
        imagej=True,
        resolution=resolution,
        metadata={"axes": "TZCYXS", "spacing": spacing, "unit": voxel_size.unit},
        compression="zlib",
    )

plantseg.io.create_h5(path: Path, stack: np.ndarray, key: str, voxel_size: Optional[VoxelSize] = None, mode: str = 'a') -> None

Create a dataset inside a h5 file from a numpy array.

Parameters:

  • path (Path) –

    path to the h5 file

  • stack (ndarray) –

    numpy array to save as dataset in the h5 file.

  • key (str) –

    key of the dataset in the h5 file.

  • voxel_size (VoxelSize, default: None ) –

    voxel size of the dataset.

  • mode (str, default: 'a' ) –

    mode to open the h5 file ['w', 'a'].

Source code in plantseg/io/h5.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
def create_h5(
    path: Path,
    stack: np.ndarray,
    key: str,
    voxel_size: Optional[VoxelSize] = None,
    mode: str = "a",
) -> None:
    """
    Create a dataset inside a h5 file from a numpy array.

    Args:
        path (Path): path to the h5 file
        stack (np.ndarray): numpy array to save as dataset in the h5 file.
        key (str): key of the dataset in the h5 file.
        voxel_size (VoxelSize): voxel size of the dataset.
        mode (str): mode to open the h5 file ['w', 'a'].

    """

    if key is None:
        raise ValueError("Key is required to create a dataset in a h5 file.")

    if key == "":
        raise ValueError("Key cannot be empty to create a dataset in a h5 file.")

    with h5py.File(path, mode) as f:
        if key in f:
            del f[key]
        f.create_dataset(key, data=stack, compression="gzip")
        # save voxel_size
        if voxel_size is not None and voxel_size.voxels_size is not None:
            f[key].attrs["element_size_um"] = voxel_size.voxels_size

plantseg.io.create_zarr(path: Path, stack: np.ndarray, key: str, voxel_size: VoxelSize, mode: str = 'a') -> None

Create a Zarr array from a NumPy array.

Parameters:

  • path (Path) –

    The path to the Zarr file.

  • stack (ndarray) –

    The NumPy array to save as a dataset.

  • key (str) –

    The internal key of the desired dataset.

  • voxel_size (VoxelSize) –

    The voxel size of the dataset.

  • mode (str, default: 'a' ) –

    The mode to open the Zarr file ['w', 'a'].

Source code in plantseg/io/zarr.py
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
def create_zarr(
    path: Path,
    stack: np.ndarray,
    key: str,
    voxel_size: VoxelSize,
    mode: str = "a",
) -> None:
    """
    Create a Zarr array from a NumPy array.

    Args:
        path (Path): The path to the Zarr file.
        stack (np.ndarray): The NumPy array to save as a dataset.
        key (str): The internal key of the desired dataset.
        voxel_size (VoxelSize): The voxel size of the dataset.
        mode (str): The mode to open the Zarr file ['w', 'a'].

    """

    if key is None:
        raise ValueError("Key cannot be None.")

    if key == "":
        raise ValueError("Key cannot be empty.")

    zarr_file = zarr.open_group(path, mode)
    zarr_file.create_dataset(key, data=stack, compression="gzip", overwrite=True)
    zarr_file[key].attrs["element_size_um"] = voxel_size.voxels_size

Tiff Utilities

plantseg.io.tiff.read_tiff_voxel_size(file_path: Path) -> VoxelSize

Returns the voxels size and the voxel units for imagej and ome style tiff (if absent returns [1, 1, 1], um)

Parameters:

  • file_path (Path) –

    path to the tiff file

Returns:

  • VoxelSize ( VoxelSize ) –

    voxel size and unit

Source code in plantseg/io/tiff.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def read_tiff_voxel_size(file_path: Path) -> VoxelSize:
    """
    Returns the voxels size and the voxel units for imagej and ome style tiff (if absent returns [1, 1, 1], um)

    Args:
        file_path (Path): path to the tiff file

    Returns:
        VoxelSize: voxel size and unit

    """
    with tifffile.TiffFile(file_path) as tiff:
        if tiff.imagej_metadata is not None:
            return _read_imagej_meta(tiff)

        elif tiff.ome_metadata is not None:
            return _read_ome_meta(tiff)

        warnings.warn("No metadata found.")
        return VoxelSize()

H5 Utilities

plantseg.io.h5.list_h5_keys(path: Path) -> list[str]

List all keys in a h5 file

Parameters:

  • path (Path) –

    path to the h5 file (Path object)

Returns:

  • keys ( list[str] ) –

    A list of keys in the h5 file.

Source code in plantseg/io/h5.py
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
def list_h5_keys(path: Path) -> list[str]:
    """
    List all keys in a h5 file

    Args:
        path (Path): path to the h5 file (Path object)

    Returns:
        keys (list[str]): A list of keys in the h5 file.

    """
    _validate_h5_file(path)

    def _recursive_find_keys(f, base="/"):
        _list_keys = []
        for key, dataset in f.items():
            if isinstance(dataset, h5py.Group):
                new_base = f"{base}{key}/"
                _list_keys += _recursive_find_keys(dataset, new_base)

            elif isinstance(dataset, h5py.Dataset):
                _list_keys.append(f"{base}{key}")
        return _list_keys

    with h5py.File(path, "r") as h5_f:
        return _recursive_find_keys(h5_f)

plantseg.io.h5.del_h5_key(path: Path, key: str, mode: str = 'a') -> None

helper function to delete a dataset from a h5file

Parameters:

  • path (Path) –

    path to the h5 file (Path object)

  • key (str) –

    key of the dataset to delete

  • mode (str, default: 'a' ) –

    mode to open the h5 file ['r', 'r+']

Source code in plantseg/io/h5.py
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
def del_h5_key(path: Path, key: str, mode: str = "a") -> None:
    """
    helper function to delete a dataset from a h5file

    Args:
        path (Path): path to the h5 file (Path object)
        key (str): key of the dataset to delete
        mode (str): mode to open the h5 file ['r', 'r+']

    """
    _validate_h5_file(path)
    with h5py.File(path, mode) as f:
        if key in f:
            del f[key]
            f.close()

plantseg.io.h5.rename_h5_key(path: Path, old_key: str, new_key: str, mode='r+') -> None

Rename the 'old_key' dataset to 'new_key'

Parameters:

  • path (Path) –

    path to the h5 file (Path object)

  • old_key (str) –

    old key name

  • new_key (str) –

    new key name

  • mode (str, default: 'r+' ) –

    mode to open the h5 file ['r', 'r+']

Source code in plantseg/io/h5.py
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
def rename_h5_key(path: Path, old_key: str, new_key: str, mode="r+") -> None:
    """
    Rename the 'old_key' dataset to 'new_key'

    Args:
        path (Path): path to the h5 file (Path object)
        old_key (str): old key name
        new_key (str): new key name
        mode (str): mode to open the h5 file ['r', 'r+']

    """
    _validate_h5_file(path)
    with h5py.File(path, mode) as f:
        if old_key in f:
            f[new_key] = f[old_key]
            del f[old_key]
            f.close()

Zarr Utilities

plantseg.io.zarr.list_zarr_keys(path: Path) -> list[str]

List all keys in a Zarr file.

Parameters:

  • path (Path) –

    The path to the Zarr file.

Returns:

  • list[str]

    list[str]: A list of keys in the Zarr file.

Source code in plantseg/io/zarr.py
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
def list_zarr_keys(path: Path) -> list[str]:
    """
    List all keys in a Zarr file.

    Args:
        path (Path): The path to the Zarr file.

    Returns:
        list[str]: A list of keys in the Zarr file.
    """

    def _recursive_find_keys(zarr_group: zarr.Group, base: Path = Path("")) -> list[str]:
        _list_keys = []
        for key, dataset in zarr_group.items():
            if isinstance(dataset, zarr.Group):
                new_base = base / key
                _list_keys.extend(_recursive_find_keys(dataset, new_base))
            elif isinstance(dataset, zarr.Array):
                _list_keys.append(str(base / key))
        return _list_keys

    zarr_file = zarr.open_group(path, "r")
    return _recursive_find_keys(zarr_file)

plantseg.io.zarr.del_zarr_key(path: Path, key: str, mode: str = 'a') -> None

Delete a dataset from a Zarr file.

Parameters:

  • path (Path) –

    The path to the Zarr file.

  • key (str) –

    The internal key of the dataset to be deleted.

  • mode (str, default: 'a' ) –

    The mode to open the Zarr file ['w', 'a'].

Source code in plantseg/io/zarr.py
189
190
191
192
193
194
195
196
197
198
199
200
201
def del_zarr_key(path: Path, key: str, mode: str = "a") -> None:
    """
    Delete a dataset from a Zarr file.

    Args:
        path (Path): The path to the Zarr file.
        key (str): The internal key of the dataset to be deleted.
        mode (str): The mode to open the Zarr file ['w', 'a'].

    """
    zarr_file = zarr.open_group(path, mode)
    if key in zarr_file:
        del zarr_file[key]

plantseg.io.zarr.rename_zarr_key(path: Path, old_key: str, new_key: str, mode: str = 'r+') -> None

Rename a dataset in a Zarr file.

Parameters:

  • path (Path) –

    The path to the Zarr file.

  • old_key (str) –

    The current key of the dataset.

  • new_key (str) –

    The new key for the dataset.

  • mode (str, default: 'r+' ) –

    The mode to open the Zarr file ['r+'].

Source code in plantseg/io/zarr.py
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
def rename_zarr_key(path: Path, old_key: str, new_key: str, mode: str = "r+") -> None:
    """
    Rename a dataset in a Zarr file.

    Args:
        path (Path): The path to the Zarr file.
        old_key (str): The current key of the dataset.
        new_key (str): The new key for the dataset.
        mode (str): The mode to open the Zarr file ['r+'].

    """
    zarr_file = zarr.open_group(path, mode)
    if old_key in zarr_file:
        zarr_file[new_key] = zarr_file[old_key]
        del zarr_file[old_key]