1

I have generated a 2D NumPy array which creates polygon perimeters to look something like:

0 0 0 0  0    0   0   0   0 0 0
0 0 0 0 256  256 256 256  0 0 0
0 0 0 0 256   0   0  256  0 0 0 
0 0 0 0 256   0   0  256  0 0 0 
0 0 0 0 256   0   0  256  0 0 0 
0 0 0 0 256   0   0  256  0 0 0 
0 0 0 0 256  256 256 256  0 0 0
0 0 0 0  0    0   0   0   0 0 0

when I use:

img = Image.fromarray(array, 'L') # from PIL library
img.save('test'.png)

I expect to open the image and see a white rectangle outline in an otherwise black backdrop but instead I get weird pseudorandom lines. I have tried replacing all the zeros with 1s and this simply changes the image to 3 straight vertical lines.

Any thoughts on what I am doing wrong?

2 Answers 2

2

Your problem is that uint8 (what used with PIL in this case) is up to 255 (not 256). This code produces a correct result:

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

im_arr = np.array(
[[0, 0, 0, 0,  0 ,   0 ,  0 ,  0 ,  0, 0 ,0],
[0, 0, 0, 0, 255,  255, 255, 255,  0, 0 ,0],
[0, 0, 0, 0, 255,   0 ,  0 , 255,  0, 0 ,0],
[0, 0, 0, 0, 255,   0 ,  0 , 255,  0, 0 ,0],
[0, 0, 0, 0, 255,   0 ,  0 , 255,  0, 0 ,0],
[0, 0, 0, 0, 255,   0 ,  0 , 255,  0, 0 ,0],
[0, 0, 0, 0, 255,  255, 255, 255,  0, 0 ,0],
[0, 0, 0, 0,  0 ,   0 ,  0 ,  0 ,  0, 0 ,0]])


im = Image.fromarray(np.uint8(im_arr))
plt.imshow(im)
plt.show()

EDIT

HI @AdamBrooks, numpy infers the list given as input according to the list's object types. for example:

>>> import numpy as np 
>>> a=np.array([1,2,3]) 
>>> a 
array([1, 2, 3]) 
>>> a.dtype 
dtype('int64') 
>>> b=np.array([1,2,3.5]) 
>>> b.dtype 
dtype('float64') 

You need to convert the input type to np.uint8 if you wish to use them as an image in your case.

Sign up to request clarification or add additional context in comments.

2 Comments

So I mistyped and was using 255 (but thank you for comment). I tried the code you suggest and it works! Can you explain what the im = Image.fromarray(np.uint8(im_arr)) is doing? Essentially, why is the np.uint8 needed? Isn't the array already in that format bc it is integers from 0 - 255?
@AdamBrooks see edit in original post.
1

Fortunately matplotlib has a special function called matshow exactly for your use case.

import numpy as np
import matplotlib.pyplot as plt

arr = np.array([[  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0],
       [  0,   0,   0,   0, 256, 256, 256, 256,   0,   0,   0],
       [  0,   0,   0,   0, 256,   0,   0, 256,   0,   0,   0],
       [  0,   0,   0,   0, 256,   0,   0, 256,   0,   0,   0],
       [  0,   0,   0,   0, 256,   0,   0, 256,   0,   0,   0],
       [  0,   0,   0,   0, 256,   0,   0, 256,   0,   0,   0],
       [  0,   0,   0,   0, 256, 256, 256, 256,   0,   0,   0],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0]])

plt.matshow(arr, cmap='gray')

enter image description here

2 Comments

@MarkSetchell you're right I changed that.
Cool - you already have my vote 😀

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.