giatools.image

Copyright 2017-2025 Leonid Kostrykin, Biomedical Computer Vision Group, Heidelberg University.

Distributed under the MIT license. See file LICENSE for detail or copy at https://opensource.org/licenses/MIT

class giatools.image.Image(data: ndarray | DaskArray, axes: str, metadata: Metadata | None = None, original_axes: str | None = None)

Bases: object

Represents an image (image pixel/voxel data and the corresponding axes metadata).

astype(dtype: DTypeLike, force_copy: bool = False, resolve_floating_to: dtype = <class 'numpy.float64'>, resolve_integer_to: dtype = <class 'numpy.int64'>, resolve_signedinteger_to: dtype = <class 'numpy.int64'>, resolve_unsignedinteger_to: dtype = <class 'numpy.uint64'>) Self

Cast the image to the specific pixel/voxel data type.

This image is not changed in place, a new image is returned. With force_copy=False (the default), the image data is copied only if necessary. The metadata is not copied (the new image references the original metadata).

The dtype parameter may be an inexact type such as np.floating, np.integer, np.signedinteger, or np.unsignedinteger. In this case, the actual data type is resolved according to the corresponding resolve_*_to parameter.

Raises:

ValueError – If conversion is not possible due to overflows.

axes: str

The axes of the image data as a string.

Example

>>> from giatools import Image
>>> image = Image.read('data/input7_uint8_zcyx.tiff')
>>> print(image.axes)
QTZYXC
clip_to_dtype(dtype: dtype, force_copy: bool = False) Self

Clips the values of this image to the valid range of the specified dtype.

This image is not changed in place. If the values of this image are already within the valid range of the target dtype, the image itself is returned (unless force_copy is True). Otherwise, a new image is returned that has the same data type as this image. The new image references the original metadata.

Raises:

TypeError – If dtype is bool.

data: ndarray | DaskArray

The image data as a NumPy array or a Dask array.

Example

>>> from giatools import Image
>>> image = Image.read('data/input7_uint8_zcyx.tiff')
>>> print(image.data.shape)
(1, 1, 25, 50, 50, 2)
get_anisotropy(axes: str | None = None, eps: float = 1e-08) Tuple[float, ...] | None

Get the anisotropy of the image pixels/voxels.

If axes is given, only the specified axes are considered for the anisotropy computation. Otherwise, all spatial axes are considered. The pixels/voxels of the image (along the specified axes) are isotropic if all returned anisotropy factors are (approximately) equal to 1.0.

The eps parameter specifies a threshold for deciding whether a pixel/voxel size is too close to zero. If any pixel/voxel size along the considered axes has absolute value smaller than eps (or is None), the resolution is treated as unknown and the method returns None.

Returns:

A tuple of anisotropy factors for the specified axes (or the spatial axes of this image if axes is None), or None if the resolution is not fully known.

Example

>>> from giatools import Image
>>> import numpy as np
>>> image = Image(np.zeros((10, 20, 30)), axes='CYX')
>>> print(image.get_anisotropy())
None
>>>
>>> image.metadata.pixel_size = (1.0, 1.2)
>>> print(image.get_anisotropy())
(1.0954451150103324, 0.9128709291752769)
>>> print(image.get_anisotropy('XY'))
(0.9128709291752769, 1.0954451150103324)
>>> image.metadata.pixel_size = (1.0, 1.0)
>>> print(image.get_anisotropy())
(1.0, 1.0)
>>>
>>> image.axes = 'ZYX'
>>> print(image.get_anisotropy())
None
>>> print(image.get_anisotropy(axes='YX'))
(1.0, 1.0)
>>> image.metadata.z_spacing = 1.0
>>> print(image.get_anisotropy())
(1.0, 1.0, 1.0)

Scaling the pixel/voxel size of each axis by the reciprocal of the corresponding anisotropy factor yields the isotropic pixel/voxel size.

Example

>>> from giatools import Image
>>> import numpy as np
>>> image = Image(np.zeros((10, 20, 30)), axes='CYX')
>>> image.metadata.pixel_size = (1.0, 1.2)  # X, Y
>>> image.metadata.z_spacing = 1.1
>>>
>>> anisotropy = image.get_anisotropy('XYZ')
>>> print(
...     image.metadata.pixel_size[0] / anisotropy[0],  # X
...     image.metadata.pixel_size[1] / anisotropy[1],  # Y
...     image.metadata.z_spacing / anisotropy[2],
... )
1.0969613104865237 1.0969613104865237 1.0969613104865237
iterate_jointly(axes: str = 'YX') Iterator[Tuple[Tuple[int | slice, ...], Self]]

Iterate over all slices of the image along the given axes.

This method yields tuples (slice, section) where slice is the slice in the source data array (this image) and section is the corresponding image section. This method is useful, for example, for applying 2-D operations to all slices of a 3-D image or time series. The order of axes in the yielded image section corresponds to the order in the axes parameter.

Note

This method requires Python 3.11 or later.

Example

>>> from giatools import Image
>>> image = Image.read('data/input7_uint8_zcyx.tiff')
>>> for _, section in image.iterate_jointly('XY'):
...     print(
...         section.data.shape,
...         section.axes,
...         section.original_axes,
...     )
...     break
(50, 50) XY YX
Raises:
  • RuntimeError – If Python version is less than 3.11.

  • ValueError – If axes contains invalid axes (must be a non-empty subset of the image axes).

metadata: Metadata

Additional metadata of the image.

Example

>>> from giatools import Image
>>> image = Image.read('data/input7_uint8_zcyx.tiff')
>>> print(image.metadata.pixel_size)
(0.43564006198286803, 0.43564006198286803)
>>> print(image.metadata.z_spacing)
0.05445500181716341
>>> print(image.metadata.unit)
um
normalize_axes_like(axes: str) Self

Normalize the axes of the image.

This image is not changed in place, a new image is returned (without copying the data). The new image references the original metadata.

Raises:
  • AssertionError – If axes is ambiguous.

  • ValueError – If one of the axis cannot be squeezed.

original_axes: str | None

The original axes of the image data as a string, if available. This is useful for keeping track of the original axes when normalizing or reordering axes.

Example

>>> from giatools import Image
>>> image = Image.read('data/input7_uint8_zcyx.tiff')
>>> print(image.original_axes)
ZCYX
property original_shape: Tuple[int, ...] | None

The shape of the original image data, if original_axes is available.

Example

>>> from giatools import Image
>>> image = Image.read('data/input7_uint8_zcyx.tiff')
>>> print(image.original_shape)
(25, 2, 50, 50)
static read(filepath: str | Path, *args: Any, normalize_axes: str | None = 'QTZYXC', **kwargs: Any) Self

Read an image from file and normalize the image axes like normalize_axes. Normalization will be (almost) skipped if normalize_axes is None.

See giatools.io.imreadraw() for details how axes are determined and treated.

reorder_axes_like(axes: str) Self

Reorder the axes of the image to match the given order.

This image is not changed in place, a new image is returned (without copying the data). The new image references the original metadata.

Raises:

ValueError – If there are spurious, missing, or ambiguous axes.

property shape: Tuple[int, ...]

The shape of the image data.

This is a short-hand for image.data.shape, provided for consistency with the original_shape attribute.

Example

>>> from giatools import Image
>>> image = Image.read('data/input7_uint8_zcyx.tiff')
>>> print(image.shape)
(1, 1, 25, 50, 50, 2)
squeeze() Self

Squeeze all singleton axes of the image.

This image is not changed in place, a new image is returned (without copying the data). The new image references the original metadata.

squeeze_like(axes: str) Self

Squeeze the axes of the image to match the axes.

This image is not changed in place, a new image is returned (without copying the data). The new image references the original metadata.

Raises:

ValueError – If one of the axis cannot be squeezed or axes is not a subset of the image axes.

write(filepath: str | Path, backend: str = 'auto') Self

Write the image to a file.

Raises:

ValueError – If the number of axes does not match the number of data dimensions.

giatools.image.default_normalized_axes: str = 'QTZYXC'

The default axes used for normalization in Image.read().