1

I want to open color image with PIL.Image.open() and convert it to a numpy array for further analysis.

The image I'm using can be downloaded here.

I've managed to open the image and display it full colour in Jupyter Notebook with no issue, but as soon as I use the getpixel method, or convert it to an array with numpy, things go wrong.

from PIL import Image
t = Image.open('radar.png')
display(t) 

This works fine so far, with the transparent part of the image showing as white on the screen.

t.show() 

First unexpected behaviour, the transparent part has been replaced with all black when it opens in the file viewer. The colours are still seen correctly.

t.getpixel((200, 200)) 

248

Second unexpected behaviour, I was expecting to see a tuple but instead it's a single number.

import numpy as np
im2arr = np.asarray(t) 
im2arr.shape

(512, 512)

Third unexpected behaviour, was expecting to get a three dimensional array.

arr2im = Image.fromarray(im2arr)
display(arr2im)

Fourth unexpected behaviour, the image is now displayed as black or white (not grayscale). It is black where it should be transparent, and white where there should be colours.

My suspicion is that PIL.Image is being somehow tricked when it opens the image the first place, as the first pixel is transparent or missing? It doesn't register as an RGBA format. I have tried the same code with full colour png that I created in paint, and it all displays correctly including 3 dimensional numpy array.

KWx
  • 310
  • 1
  • 10
  • What do you think/expect is the “correct” way to display the transparency, and why? Yes it sounds `getpixel` and `display` are showing the transparency layer and not the RGB. What have you tried to see what the content/format of the image `t` is - will opencv tell you what it thinks the format is? – DisappointedByUnaccountableMod Aug 31 '19 at 10:19
  • @barny I suppose I don't mind how it displays transparent, whether white or black or checkered. I just thought it odd that jupyter notebook displays it differently to `t.show()`. My main aim is to get to a numpy array to do analysis. `t.format` gives me back 'PNG'. – KWx Aug 31 '19 at 11:05
  • @barny `t.mode` is 'P' – KWx Sep 01 '19 at 10:31

1 Answers1

2

Your image is a "palette Alpha" image. That means, instead of having RGBA channels, it has a single channel and an 8-bit index is stored for each pixel. That index looks up an RGBA value in the palette of 256 colours.

You can open it and get what you expect like this which will convert each index into an RGBA value:

im = Image.open('weather.png').convert('RGBA')

Now if you convert to Numpy array, you will get 4 channels, namely RGBA:

n = np.array(im)
print(n.shape)                # prints (512,512,4)

I did a more detailed explanation of palette images here.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • This is it. Your detailed link is also helpful @Mark Setchell, as I think it will be easier for me to do my analysis on the original palette format. – KWx Sep 01 '19 at 10:33
  • For anyone else in a similar situation, you can convert from a Palette image to a numpy array and back again using the following code. This way you can `import numpy as np from PIL import Image t = Image.open('radar.png') im2arr = np.asarray(t) arr2im = Image.fromarray(im2arr) arr2im.putpalette(t.getpalette()) display(arr2im)` – KWx Sep 01 '19 at 11:16