1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
Multidimensional Readers
========================
.. ipython:: python
:suppress:
from pims.tests.test_common import save_dummy_png, clean_dummy_png
from itertools import product
filenames = ['img-t{0}z{1}c{2}.png'.format(i, j, z) for i, j, z in product(range(4), range(10), range(2))]
save_dummy_png('.', filenames, (64, 128))
from pims import ImageSequenceND
images = ImageSequenceND('img-*.png', axes_identifiers='tzc')
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 :doc:`image_sequence` or :doc:`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:
.. ipython:: python
images.sizes
Axes bundling
-------------
The ``bundle_axes`` property defines which axes will be present in a single frame.
The ``frame_shape`` property is changed accordingly:
.. ipython:: python
images.bundle_axes = 'czyx'
images.frame_shape
images.bundle_axes = 'yx'
images.frame_shape
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:
.. ipython:: python
images.iter_axes = 't'
len(images)
When multiple axes are provided to ``iter_axes``, a nested iteration will be
performed in which the last element will iterate fastest:
.. ipython:: python
images.iter_axes = 'tz'
len(images) # 4 * 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``:
.. ipython:: python
images.bundle_axes = 'zyx'
images.iter_axes = 't'
images.default_coords['c'] = 1
images[2]; # returns the 3D image at t == 2 and c = 1
.. ipython:: python
:suppress:
clean_dummy_png('.', filenames)
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.
.. code-block:: python
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)
|