from pims.base_frames import FramesSequenceND
from pims.frame import Frame
try:
import imageio
except ImportError:
imageio = None
try:
import imageio_ffmpeg
try:
imageio_ffmpeg.get_ffmpeg_exe()
except RuntimeError:
imageio_ffmpeg = None
except ImportError:
imageio_ffmpeg = None
def available():
return imageio is not None
def ffmpeg_available():
return (imageio is not None) and (imageio_ffmpeg is not None)
[docs]class ImageIOReader(FramesSequenceND):
class_priority = 6
propagate_attrs = ['frame_shape', 'pixel_type', 'metadata',
'get_metadata_raw', 'reader_class_name']
[docs] @classmethod
def class_exts(cls):
exts = {'tiff', 'bmp', 'cut', 'dds', 'exr', 'g3', 'hdr', 'iff', 'j2k',
'jng', 'jp2', 'jpeg', 'jpg', 'koala', 'pbm', 'pbmraw', 'pcd',
'pcx', 'pfm', 'pgm', 'pgmraw', 'pict', 'png', 'ppm', 'ppmraw',
'psd', 'ras', 'raw', 'sgi', 'targa', 'fi_tiff', 'wbmp', 'webp',
'xbm', 'xpm', 'ico', 'gif', 'dicom', 'npz', 'fits', 'itk',
'gdal', 'dummy', 'gif', 'ffmpeg', 'avbin', 'swf', 'fits',
'gdal', 'ts', 'tif'}
return exts.union(cls.additional_class_exts())
[docs] @classmethod
def additional_class_exts(cls):
"""If imageio-ffmpeg is available, more filetypes are supported."""
movie_exts = set()
if imageio_ffmpeg is not None:
movie_exts = movie_exts.union(
{'mov', 'avi', 'mpg', 'mpeg', 'mp4', 'mkv', 'wmv'}
)
return movie_exts
def __init__(self, filename, **kwargs):
if imageio is None:
raise ImportError('The ImageIOReader requires imageio and '
'(for imageio >= 2.5) imageio-ffmpeg to work.')
super(self.__class__, self).__init__()
self.reader = imageio.get_reader(filename, **kwargs)
self.filename = filename
self._len = self.reader.get_length()
# fallback to count_frames, for newer imageio versions
if self._len == float("inf"):
self._len = self.reader.count_frames()
try:
int(self._len)
except OverflowError:
self.reader.close()
raise NotImplementedError(
"Do not know how to deal with infinite readers"
)
first_frame = self.get_frame_2D(t=0)
self._shape = first_frame.shape
self._dtype = first_frame.dtype
self._setup_axes()
self._register_get_frame(self.get_frame_2D, 'yx')
def _setup_axes(self):
"""Setup the xyctz axes, iterate over t axis by default
"""
if self._shape[1] > 0:
self._init_axis('x', self._shape[1])
if self._shape[0] > 0:
self._init_axis('y', self._shape[0])
if self._len > 0:
self._init_axis('t', self._len)
if len(self.sizes) == 0:
raise EmptyFileError("No axes were found for this file.")
# provide the default
self.iter_axes = self._guess_default_iter_axis()
def _guess_default_iter_axis(self):
"""
Guesses the default axis to iterate over based on axis sizes.
Returns:
the axis to iterate over
"""
priority = ['t', 'z', 'c', 'v']
found_axes = []
for axis in priority:
try:
current_size = self.sizes[axis]
except KeyError:
continue
if current_size > 1:
return axis
found_axes.append(axis)
return found_axes[0]
def get_frame_2D(self, **coords):
i = coords['t'] if 't' in coords else 0
frame = self.reader.get_data(i)
return Frame(frame, frame_no=i, metadata=frame.meta)
def get_metadata(self):
return self.reader.get_meta_data(None)
def __len__(self):
return self._len
def __iter__(self):
iterable = self.reader.iter_data()
for i in range(len(self)):
frame = next(iterable)
yield Frame(frame, frame_no=i, metadata=frame.meta)
@property
def frame_rate(self):
return self.get_metadata()['fps']
@property
def frame_shape(self):
return self._shape
@property
def pixel_type(self):
return self._dtype
[docs] def close(self):
self.reader.close()
super().close()