2

I have to load a gif containing a binary mask in Python.

inputmask

import numpy as np

from PIL import Image
import imageio

from matplotlib import pyplot as plt


maskPIL = np.array(Image.open('mask.gif'))


maskIO = np.array(imageio.imread('mask.gif'))


plt.subplot(1,2,1)
plt.title('PIL Mask')
plt.imshow(maskPIL,cmap='Greys')


plt.subplot(1,2,2)
plt.title('ImageIO Mask')
plt.imshow(maskIO,cmap='Greys')

plt.show()

Result

Why are the 2 methods behaving differently?

PIL version: 8.0.1

imageio version: 2.9.0

Mr Vinagi
  • 390
  • 3
  • 12
  • Why are they behaving differently? Because they're entirely different implementations. That aside, try with an RGB PNG instead of a palettized GIF? – AKX Apr 13 '21 at 15:36

1 Answers1

2

If you do this:

im = Image.open('mask.gif')
print(im)

Output

<PIL.GifImagePlugin.GifImageFile image mode=P size=683x512 at 0x7FC0C86FF430>

you will see that your image is a palette image - because mode=P. That means that the values in the image are not RGB or greyscale values, but indices into a palette. If you look at the palette:

np.array(im.getpalette()).reshape(256,3)
Out[25]: 
array([[255, 255, 255],      <--- palette entry 0
       [  0,   0,   0],      <--- palette entry 1
       [  2,   2,   2],
       [  3,   3,   3],
       [  4,   4,   4],
       [  5,   5,   5],
       ...
       ...

you will see that entry 0 is rgb(255,255,255), so that means wherever you have zero in your image, it should display white! And wherever you have one in your image, it should display black.

If you want the proper values, as greyscale, you need to comvert the image to L mode, then all your pixels will be actual grey values:

maskPIL = np.array(Image.open('mask.gif').convert('L'))

Fuller explanation here.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432