imageio icon indicating copy to clipboard operation
imageio copied to clipboard

imageio v3 imwrite writes 3D tiff files that don't roundtrip with imread

Open anntzer opened this issue 3 years ago • 3 comments

A 3D tiff file written with the tifffile module is correctly loaded as a 3D array by both tifffile and imageio3. If the file is instead written by imageio3, only the first page gets loaded (one would need to use imiter instead to load it).

In [7]: import tifffile, imageio.v3 as iio, numpy as np
   ...: tifffile.imwrite("/tmp/a.tiff", np.ones((10, 64, 64), "u4"))
   ...: print(tifffile.imread("/tmp/a.tiff").shape)
   ...: print(iio.imread("/tmp/a.tiff").shape)
   ...: iio.imwrite("/tmp/b.tiff", np.ones((10, 64, 64), "u4"))
   ...: print(tifffile.imread("/tmp/b.tiff").shape)
   ...: print(iio.imread("/tmp/b.tiff").shape)
(10, 64, 64)
(10, 64, 64)
(64, 64)
(64, 64)

FWIW, looking at the tiff metadata, I note that "a.tiff" (tifffile) contains ImageDescription: {"shape": [10, 64, 64]} on the first plane only, wheread "b.tiff" (imageio3) contains ImageDescription: {"shape": [64, 64]} on each individual plane.

The problem is present even with #851. On imageio2, the problem was not present -- one had to explicitly call volwrite or mimwrite depending on the desired semantics, and the reading correctly roundtripped (volwrite -> volread, mimwrite -> mimread).

anntzer avatar Jul 27 '22 21:07 anntzer

Thanks for the report @anntzer . I can reproduce this on master.

It is related to the way batches of images are auto-detected in the legacy plugin wrapper. When I do the following it seems to work as it should:

iio.imwrite("b.tiff", np.ones((1, 10, 64, 64), "u4")
print(iio.imread("b.tiff").shape)
# (10, 64, 64)
print(tifffile.imread("b.tiff").shape)
# (10, 64, 64)

or on #851

iio.imwrite("b.tiff", np.ones((10, 64, 64), "u4"), is_batch=False)
print(iio.imread("b.tiff").shape)
# (10, 64, 64)
print(tifffile.imread("b.tiff").shape)
# (10, 64, 64)

I will try to have a look if it is an easy change or something more complex later today. If it is more complex it will have to wait until next week. My PhD thesis will go to print early next week so today and tomorrow are the final days for me to do any touch-ups on that document, which takes priority.

FirefoxMetzger avatar Jul 28 '22 04:07 FirefoxMetzger

Okay, I gave it a quick test. The following change does resolve the problem and it agrees with our current test suite:

@@ -185,12 +185,8 @@ class LegacyPlugin(PluginV3):
             pass
         elif isinstance(ndimage, (list, tuple)):
             is_batch = True
-        elif ndimage.ndim == 2:
-            is_batch = False
-        elif ndimage.ndim == 3 and ndimage.shape[-1] < 5:
-            is_batch = False
         else:
-            is_batch = True
+            is_batch = False

         if not is_batch:
             ndimage = np.asarray(ndimage)[None, ...]

However, it breaks writing video when using the V3 API in combination with imageio-ffmpeg, i.e., iio.imwrite("some.mp4", frame_batch) won't work unless one uses the pyav plugin instead. Long story short, I won't be able to fix this this week, but will have to tackle it next week.

FirefoxMetzger avatar Jul 28 '22 10:07 FirefoxMetzger

No worries, good luck with the PhD finalization :)

anntzer avatar Jul 28 '22 10:07 anntzer