giatools¶
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(data: ndarray | DaskArray, axes: str, metadata: Metadata | None = None, original_axes: str | None = None)¶
Bases:
objectRepresents 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
axesparameter.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_shapeattribute.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.
- class giatools.ImageProcessor(*args: Image, **kwargs: Image)¶
Bases:
objectProcesses one or more images with the same shape and axes, and yields one or more output images of the same shape.
- Raises:
ValueError – If no input images are provided, or if the input images do not have the same shape and axes.
- create_output_image(key: Any, dtype: dtype) Image¶
Create and return an output image with the given key and data type.
The output image will have the same shape, axes, and metadata as the input images. The metadata is copied.
- Raises:
ValueError – If an output image with the given key already exists.
- image0: Image¶
An input image that is used to determine the shape, axes, and metadata of the output images.
- inputs: MappingProxyType¶
Dictionary of the input images, keyed by strings (keyword arguments) or integers (positional arguments).
- process(joint_axes: str, output_dtype_hints: Dict[Any, Literal['binary', 'bool', 'float16', 'float32', 'float64', 'floating', 'preserve', 'preserve_floating']] | None = None) Iterator[ProcessorIteration]¶
Iterate over all slices of the input images along the given axes, yielding
ProcessorIterationobjects that provide access to the corresponding sections of the input and output images.The axes in the yielded image sections correspond exactly to the joint_axes parameter (in the given order).
The data written to the output images in each iteration is automatically normalized according to the policy specified for the respective output image via the output_dtype_hints mapping (dictionary of output keys to the respective policies; see
apply_output_dtype_hint()for a list of possible values).Note
This method requires Python 3.11 or later.
Example
>>> from giatools import Image, ImageProcessor >>> image = Image.read('data/input4_uint8.png') >>> print(image.axes, image.data.shape) QTZYXC (1, 1, 1, 10, 10, 3) >>> >>> proc = ImageProcessor(image) >>> for section in proc.process('XY'): ... section['result'] = ( ... section[0].data > section[0].data.mean() ... ) >>> >>> import numpy as np >>> expected_result = np.stack( ... [ ... image.data[..., c] > image.data[..., c].mean() ... for c in range(image.data.shape[-1]) ... ], ... axis=-1, ... ) >>> print( ... np.allclose( ... proc.outputs['result'].data, ... expected_result, ... ), ... proc.outputs['result'].metadata == image.metadata, ... ) True True
- Raises:
RuntimeError – If Python version is less than 3.11.
ValueError – If joint_axes contains invalid axes (must be a non-empty subset of the image axes); or if output_dtype_hints contains invalid values.
- class giatools.ToolBaseplate(*args, params_required=True, **kwargs)¶
Bases:
objectBaseplate for command-line tools in Galaxy Image Analysis.
Example
The following example implements a simple thresholding tool that reads an input image from a file path and performs thresholding based on the mean pixel value. Only the YX axes are processed jointly. This means that, for multi-channel images, the thresholding is applied independently to each channel. For 3-D images, the thresholding is also applied independently to each z-slice, and for multi-frame images (time series), it is applied independently to each frame. The output is written as a binary image (uint8 with 0/255 labels).
import giatools if __name__ == '__main__': tool = giatools.ToolBaseplate(params_required=False) tool.add_input_image('input') tool.add_output_image('output') for sect in tool.run('YX', output_dtype_hint='binary'): sect['output'] = ( sect['input'].data > sect['input'].data.mean() )
This code forges a command-line tool that can cope with different input image formats (including TIFF and Zarr), a variety of different image axes in arbitrary orders, and preserves important image metadata that can be crucial for subsequent analysis steps. The tool can be executed from the command line as follows:
$ python -m examples.cli --help usage: cli.py [-h] [--params PARAMS] [--verbose] --input INPUT --output OUTPUT options: -h, --help show this help message and exit --params PARAMS --verbose --input INPUT --output OUTPUT
The –params argument is optional in this example, but could be used to provide the path to a JSON file that is generated as configfile from the Galaxy tool wrapper.
$ python -m examples.cli --verbose --input data/input4_uint8.png --output /tmp/output.png [input] Input image axes: YXC [input] Input image shape: (10, 10, 3) [input] Input image dtype: uint8 [output] Output image axes: YXC [output] Output image shape: (10, 10, 3) [output] Output image dtype: uint8
- add_input_image(key: str, required: bool = True)¶
Add a named input image argument to the parser.
- Raises:
ValueError – If the key is already used.
- add_output_image(key: str, required: bool = True)¶
Add an argument for a path for an output image to the parser.
- Raises:
ValueError – If the key is already used.
- args: SimpleNamespace | None = None¶
Command-line arguments parsed from the command line (including the loaded input images).
- create_processor() ImageProcessor¶
Create a
giatools.image_processor.ImageProcessorwith the input images parsed from the command line. Thegiatools.image_processor.ImageProcessoris returned and also made available via theprocessorattribute.The command line arguments are obtained via the
parse_args()method unless theargsattribute is already populated (which has precedence).
- input_keys: List[str]¶
List of input image keys.
- output_keys: List[str]¶
List of output image keys.
- parse_args() SimpleNamespace¶
Parse the command-line arguments and return a namespace that contains the JSON-encoded parameters, the input images, and the output image file paths. The
argsattribute is also populated.
- processor: ImageProcessor | None = None¶
The
giatools.image_processor.ImageProcessorinstantiated latest via thecreate_processor()method.
- run(joint_axes: str, write_output_images: bool = True, **kwargs: str) Iterator[ProcessorIteration]¶
Use the
create_processor()method to spin up agiatools.image_processor.ImageProcessorwith the input images parsed from the command line, and write the output images to the file paths specified via command line arguments (if write_output_images is True).Note
This method requires Python 3.11 or later.
- Raises:
RuntimeError – If Python version is less than 3.11.
- write_output_images()¶
Write the output images to the file paths specified via command line arguments.
The output images are obtained from the
giatools.image_processor.ImageProcessorreferenced by theprocessorattribute. The command line arguments must be provided via theargsattribute.
- giatools.VERSION = '0.7.3'¶
Alias for backward compatibility.
- giatools.require_backend(name: str)¶
Ensures that the backend with the given name is available.
- Raises:
ImportError – If the backend is not available.