Multidimensional Readers¶
Multidimensional files are files that have for instance an extra z-axis (making
the image 3D, an extra channel axis, or a multipoint axis. PIMS provides a
flexible and uniform interface for working with these kind of files through the
base class FramesSequenceND
. The readers ImageSequenceND
and Bioformats
(see ImageSequence or Bioformats).
are based on this baseclass and provide the axis-aware methods describe below.
To avoid ambiguity, we call a point along one axis a coordinate. The word
index refers to the working of frames[index]
. The index is equal to the
coordinate along the iterating axis (normally, t), except when the iterating
axis is nested (see below).
The names and sizes of each axis is provided with the sizes
property:
In [1]: images.sizes
Out[1]: {'c': 2, 't': 4, 'x': 128, 'y': 64, 'z': 10}
Axes bundling¶
The bundle_axes
property defines which axes will be present in a single frame.
The frame_shape
property is changed accordingly:
In [2]: images.bundle_axes = 'czyx'
In [3]: images.frame_shape
Out[3]: (2, 10, 64, 128)
In [4]: images.bundle_axes = 'yx'
In [5]: images.frame_shape
Out[5]: (64, 128)
Currently, the last two axes have to be 'yx'
. For multi-symbol axis names,
provide a list like this: images.bundle_axes = ['one', 'two']
.
Axes iteration¶
The iter_axes
property defines which axis will be used as the index axis. The
reader length is updated accordingly:
In [6]: images.iter_axes = 't'
In [7]: len(images)
Out[7]: 4
When multiple axes are provided to iter_axes
, a nested iteration will be
performed in which the last element will iterate fastest:
In [8]: images.iter_axes = 'tz'
In [9]: len(images) # 4 * 10
Out[9]: 40
In [10]: images[12]; # returns the image at t == 1 and z = 2
Default coordinates¶
What if an axis is not present in bundle_axes
and iter_axes
? Then the
default coordinate is returned, as defined in the dictionary default_coords
:
In [11]: images.bundle_axes = 'zyx'
In [12]: images.iter_axes = 't'
In [13]: images.default_coords['c'] = 1
In [14]: images[2]; # returns the 3D image at t == 2 and c = 1
Make your own multidimensional reader¶
Making a multidimensional reader class yourself is simple. The following
example is already a fully-functioning multidimensional reader. The crucial
method here is _register_get_frame
, that registers a get_frame
method
and tells the reader which axes to expect from that method. You can also define
multiple get_frame
methods to increase the reader performance.
The reader then figures out how to efficiently use this function, to present
the image in the shape that corresponds with the bundle_axes
settings.
from pims import FramesSequenceND
import numpy as np
class IndexReturningReader(FramesSequenceND):
@property
def pixel_type(self):
return np.uint8 # the pixel datatype
def __init__(self, size_c, size_t, size_z):
# first call the baseclass initialization
super(IndexReturningReader, self).__init__()
self._init_axis('x', 3)
self._init_axis('y', 1)
self._init_axis('c', size_c)
self._init_axis('t', size_t)
self._init_axis('z', size_z)
# register the get_frame function
self._register_get_frame(self.get_frame_func, 'yx')
def get_frame_func(self, c, t, z):
return np.array([[c, t, z]], dtype=np.uint8)