diff --git a/README.md b/README.md
index 727dd42..f3f1d84 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,6 @@ Formats readable by pims include:
PIMS is based on readers by:
* [scikit-image](http://scikit-image.org/)
-* [matplotlib](http://matplotlib.org/)
* [ffmpeg](https://www.ffmpeg.org/) and [PyAV](http://mikeboers.github.io/PyAV/) (video formats such as AVI, MOV)
* [jpype](http://jpype.readthedocs.org/en/latest/) (interface with Bio-formats)
* [Pillow](http://pillow.readthedocs.org/en/latest/) (improved TIFF support)
diff --git a/doc/source/image_sequence.rst b/doc/source/image_sequence.rst
index 866026c..4bf71d5 100644
--- a/doc/source/image_sequence.rst
+++ b/doc/source/image_sequence.rst
@@ -41,6 +41,6 @@ popular formats like PNG, JPG, TIFF, and others. PIMS requires **one of
the following** packages, in order of decreasing preference.
* `scikit-image `_
-* `matplotlib `_
+* `imageio `_
Scikit-image is installed with the PIMS conda package.
diff --git a/pims/image_reader.py b/pims/image_reader.py
index 4b55718..0d6de62 100644
--- a/pims/image_reader.py
+++ b/pims/image_reader.py
@@ -6,26 +6,13 @@
from pims.base_frames import FramesSequence, FramesSequenceND
from pims.frame import Frame
-# If scikit-image is not available, use matplotlib (with a warning) instead.
-import warnings
try:
from skimage.io import imread
except ImportError:
- try:
- from matplotlib.pyplot import imread
- # imread() works differently between scikit-image and matplotlib.
- # We don't require users to have scikit-image,
- # but if we fall back to matplotlib, make sure the user
- # is aware of the consequences.
- ski_preferred = ("PIMS image_reader.py could not find scikit-image. "
- "Falling back to matplotlib's imread(), which uses floats "
- "instead of integers. This may break your scripts. \n"
- "(To ignore this warning, include the line "
- '"warnings.simplefilter("ignore", RuntimeWarning)" '
- "in your script.)")
- warnings.warn(RuntimeWarning(ski_preferred))
- except ImportError:
- imread = None
+ import imageio
+
+ def imread(*args, **kwargs): # Strip metadata for consistency.
+ return np.asarray(imageio.imread(*args, **kwargs))
class ImageReader(FramesSequence):
@@ -40,11 +27,6 @@ def class_exts(cls):
class_priority = 12
def __init__(self, filename, **kwargs):
- if imread is None:
- raise ImportError("One of the following packages are required for "
- "using the ImageReader: "
- "matplotlib or scikit-image.")
-
self._data = imread(filename, **kwargs)
def get_frame(self, i):
@@ -74,10 +56,6 @@ def class_exts(cls):
class_priority = 11
def __init__(self, filename, **kwargs):
- if imread is None:
- raise ImportError("One of the following packages are required for "
- "using the ImageReaderND: "
- "matplotlib or scikit-image.")
super(ImageReaderND, self).__init__()
self._data = Frame(imread(filename, **kwargs), frame_no=0)
diff --git a/pims/image_sequence.py b/pims/image_sequence.py
index 5bcc9d4..e6b7c26 100644
--- a/pims/image_sequence.py
+++ b/pims/image_sequence.py
@@ -17,20 +17,9 @@
import pims
from pims.base_frames import FramesSequence, FramesSequenceND
from pims.frame import Frame
+from pims.image_reader import imread
from pims.utils.sort import natural_keys
-# skimage.io.plugin_order() gives a nice hierarchy of implementations of imread.
-# If skimage is not available, go down our own hard-coded hierarchy.
-has_skimage = False
-try:
- from skimage.io import imread
- has_skimage = True
-except ImportError:
- try:
- from matplotlib.pyplot import imread
- except ImportError:
- imread = None
-
class ImageSequence(FramesSequence):
"""Read a directory of sequentially numbered image files into an
@@ -68,11 +57,11 @@ class ImageSequence(FramesSequence):
>>> frame_shape = video.frame_shape # Pixel dimensions of video
"""
def __init__(self, path_spec, plugin=None):
- if not has_skimage:
+ if not imread.__module__.startswith("skimage"):
if plugin is not None:
warn("A plugin was specified but ignored. Plugins can only "
"be specified if scikit-image is available. Instead, "
- "ImageSequence will try using matplotlib")
+ "ImageSequence will use imageio")
self.kwargs = dict()
else:
self.kwargs = dict(plugin=plugin)
@@ -94,10 +83,6 @@ def __del__(self):
self.close()
def imread(self, filename, **kwargs):
- if imread is None:
- raise ImportError("One of the following packages are required for "
- "using the ImageSequence reader: "
- "scikit-image or matplotlib.")
if self._is_zipfile:
file_handle = BytesIO(self._zipfile.read(filename))
return imread(file_handle, **kwargs)
diff --git a/pims/tests/test_common.py b/pims/tests/test_common.py
index bd35ae8..91d048e 100644
--- a/pims/tests/test_common.py
+++ b/pims/tests/test_common.py
@@ -48,12 +48,6 @@ def _skip_if_no_tifffile():
raise unittest.SkipTest('tifffile not installed. Skipping.')
-def _skip_if_no_imread():
- if pims.image_sequence.imread is None:
- raise unittest.SkipTest('ImageSequence requires either matplotlib or'
- ' scikit-image. Skipping.')
-
-
def _skip_if_no_skimage():
try:
import skimage
@@ -61,12 +55,6 @@ def _skip_if_no_skimage():
raise unittest.SkipTest('skimage not installed. Skipping.')
-def _skip_if_no_PIL():
- import pims.tiff_stack
- if not pims.tiff_stack.PIL_available():
- raise unittest.SkipTest('PIL/Pillow not installed. Skipping.')
-
-
def assert_image_equal(actual, expected):
if np.issubdtype(actual.dtype, np.integer):
assert_equal(actual, expected)
@@ -183,7 +171,6 @@ def compare_slice_to_list(actual, expected):
class TestRecursiveSlicing(unittest.TestCase):
def setUp(self):
- _skip_if_no_imread()
class DemoReader(pims.ImageSequence):
def imread(self, filename, **kwargs):
return np.array([[filename]])
@@ -382,7 +369,6 @@ def test_simple_negative_index(self):
class TestImageReaderTIFF(_image_single, unittest.TestCase):
def setUp(self):
- _skip_if_no_imread()
self.filename = os.path.join(path, 'stuck.tif')
self.frame0 = np.load(os.path.join(path, 'stuck_frame0.npy'))
self.frame1 = np.load(os.path.join(path, 'stuck_frame1.npy'))
@@ -395,7 +381,6 @@ def setUp(self):
class TestImageReaderPNG(_image_single, unittest.TestCase):
def setUp(self):
- _skip_if_no_imread()
self.klass = pims.ImageReader
self.kwargs = dict()
self.expected_shape = (10, 11)
@@ -408,7 +393,6 @@ def setUp(self):
class TestImageReaderND(_image_single, unittest.TestCase):
def setUp(self):
- _skip_if_no_imread()
self.klass = pims.ImageReaderND
self.kwargs = dict()
self.expected_shape = (10, 11, 3)
@@ -516,7 +500,6 @@ def check_skip(self):
pass
def setUp(self):
- _skip_if_no_PIL()
self.filename = os.path.join(path, 'stuck.tif')
self.frame0 = np.load(os.path.join(path, 'stuck_frame0.npy'))
self.frame1 = np.load(os.path.join(path, 'stuck_frame1.npy'))
@@ -572,9 +555,6 @@ def test_metadata(self):
class TestOpenFiles(unittest.TestCase):
- def setUp(self):
- _skip_if_no_PIL()
-
def test_open_png(self):
self.filenames = ['dummy_png.png']
shape = (10, 11)
@@ -583,7 +563,6 @@ def test_open_png(self):
clean_dummy_png(path, self.filenames)
def test_open_pngs(self):
- _skip_if_no_imread()
self.filepath = os.path.join(path, 'image_sequence')
self.filenames = ['T76S3F00001.png', 'T76S3F00002.png',
'T76S3F00003.png', 'T76S3F00004.png',
diff --git a/pims/tests/test_frame.py b/pims/tests/test_frame.py
index 7d55da5..9d64318 100644
--- a/pims/tests/test_frame.py
+++ b/pims/tests/test_frame.py
@@ -7,13 +7,6 @@
from pims.frame import Frame
-def _skip_if_no_PIL():
- try:
- from PIL import Image
- except ImportError:
- raise unittest.SkipTest('PIL/Pillow not installed. Skipping.')
-
-
def _skip_if_no_jinja2():
try:
import jinja2
@@ -39,7 +32,6 @@ def test_creation_md():
def test_repr_html_():
- _skip_if_no_PIL()
_skip_if_no_jinja2()
# This confims a bugfix, where 16-bit images would raise
# an error.
diff --git a/pims/tests/test_imseq.py b/pims/tests/test_imseq.py
index 380cc39..06a7b0d 100644
--- a/pims/tests/test_imseq.py
+++ b/pims/tests/test_imseq.py
@@ -13,7 +13,7 @@
from pims.tests.test_common import (_image_series,
clean_dummy_png, save_dummy_png,
- _skip_if_no_skimage, _skip_if_no_imread)
+ _skip_if_no_skimage)
path, _ = os.path.split(os.path.abspath(__file__))
path = os.path.join(path, 'data')
@@ -83,7 +83,6 @@ def tearDown(self):
class TestImageSequenceAcceptsList(_image_series, unittest.TestCase):
def setUp(self):
- _skip_if_no_imread()
self.filepath = os.path.join(path, 'image_sequence')
self.filenames = ['T76S3F00001.png', 'T76S3F00002.png',
'T76S3F00003.png', 'T76S3F00004.png',
@@ -107,7 +106,6 @@ def tearDown(self):
class TestImageSequenceNaturalSorting(_image_series, unittest.TestCase):
def setUp(self):
- _skip_if_no_imread()
self.filepath = os.path.join(path, 'image_sequence')
self.filenames = ['T76S3F1.png', 'T76S3F20.png',
'T76S3F3.png', 'T76S3F4.png',
@@ -150,7 +148,6 @@ def tearDown(self):
class ImageSequenceND(_image_series, unittest.TestCase):
def setUp(self):
- _skip_if_no_imread()
self.filepath = os.path.join(path, 'image_sequence3d')
self.filenames = ['file_t001_z001_c1.png',
'file_t001_z001_c2.png',
@@ -212,7 +209,6 @@ def test_sizeC(self):
class ImageSequenceND_RGB(_image_series, unittest.TestCase):
def setUp(self):
- _skip_if_no_imread()
self.filepath = os.path.join(path, 'image_sequence3d')
self.filenames = ['file_t001_z001_c1.png',
'file_t001_z002_c1.png',
@@ -249,7 +245,6 @@ def tearDown(self):
class ReaderSequence(_image_series, unittest.TestCase):
def setUp(self):
- _skip_if_no_imread()
self.filepath = os.path.join(path, 'image_sequence3d')
self.filenames = ['file001.png',
'file002.png',
diff --git a/setup.py b/setup.py
index 1e81781..2539ad3 100644
--- a/setup.py
+++ b/setup.py
@@ -16,7 +16,12 @@
cmdclass=versioneer.get_cmdclass(),
description="Python Image Sequence",
author="PIMS Contributors",
- install_requires=['slicerator>=0.9.8', 'six>=1.8', 'numpy>=1.19'],
+ install_requires=[
+ 'imageio',
+ 'numpy>=1.19',
+ 'six>=1.8',
+ 'slicerator>=0.9.8',
+ ],
author_email="dallan@pha.jhu.edu",
url="https://github.com/soft-matter/pims",
packages=["pims", "pims.utils", "pims.tests"],