3

I am trying to create GIFs using imageio. This is fairly straightforward; however, the quality of the images is poor. They appear to be interpolated. See the figures below.

I am creating the GIF using the code shown below. I've tried tracing the the how the image is produced inside the source code and the issue seems to be coming from PIL.

from PIL import Image
import imageio
import numpy as np
import matplotlib.pyplot as plt

outdir = r"where/you/want/it/to/go.gif"
frames = np.round(100+20*np.random.randn(10, 40, 40)).astype(np.uint8)

# Create single gif frame with PIL
im = Image.fromarray(frames[0])
im.save(outdir)

# Create gif with imageio
imageio.mimsave(outdir, frames)

I want a GIF that looks like the image on top (no interpolation) which I produced with matplotlib. The image on the bottom is a single frame produced using imageio.

Image displayed with matplotlib with interpolation set to "none"

Image produced from PIL. Note what appears to be spatial interpolation

Stephen Hartzell
  • 660
  • 1
  • 7
  • 17

1 Answers1

0

I tried to reproduce the problem but - as far as I can tell - there is no interpolation happening inside of either ImageIO or Pillow:

from PIL import Image
import imageio as iio
import numpy as np
import io

for _ in range(100):
    expected_frames = np.round(100+20*np.random.randn(10, 40, 40)).astype(np.uint8)

    # test writing with pillow
    pil_buffer = io.BytesIO()
    im = Image.fromarray(expected_frames[0])
    gif_bytes = im.save(pil_buffer, format="GIF")
    actual_pil = iio.v3.imread(pil_buffer, mode="L")
    assert np.all(actual_pil == expected_frames[0])

    # test writing with ImageIO
    gif_bytes = iio.v3.imwrite("<bytes>", expected_frames, format="GIF") 
    actual_iio = iio.v3.imread(gif_bytes, index=None, mode="L")
    assert np.all(actual_iio == expected_frames)

print("No roundtrip modified any pixels.")

So I think that either

  • There may have been a bug in Pillow or ImageIO that has since been fixed (it has been 3 years)
  • The tool/application you used to display the second image interpolates as you zoom into the image (since that image is 200x200 px instead of being 40x40 pixels)
FirefoxMetzger
  • 2,880
  • 1
  • 18
  • 32