-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Image.putdata() NumPy usability suggestion #5858
Description
This could be a feature request, an ask for a doc change or for better error reporting.
When I grab an image, suck it into a numpy array, process it, and then spit it back into an image, I hit what appears to be a silent fail when the data given to Image.putdata() is a 2D numpy array instead of 1D (nominally a sequence), or is a float array instead of uint8.
My naive expectation was to do this:
image_array = np.array(source_image)
# ...do something to the data via numpy that might inadvertently
# change it to float64, still with int-equivalent values...
new_image = Image.new('P', (source_image.size))
new_image.putdata(image_array)If I don't coerce the array to uint8 and 1D, I still get an image, but with all values set to 0, and Pillow is silent on what (again, naively) appears to be a failure.
(I now know new_image.putdata(image_array.ravel().astype(int)) works, but it wan't obvious. :)
While making the docs more precise or adding better error reporting are both easier responses, it would seem that this isn't an uncommon use case, and it might be a nice ease-of-use change to have putdata accept a 2D array if it's the same size as the image, and also to coerce the data to ints, as a better silent option.
I'm running Pillow 8.4.0, python 3.10 on osx Mojave 10.14.6.
Thanks!
Test code:
from PIL import Image
import numpy as np
palette_data = [
0, 0, 192,
0, 33, 76,
0, 192, 0,
0, 192, 192,
9, 9, 9,
19, 19, 19,
29, 29, 29,
50, 0, 106,
192, 0, 0,
192, 0, 192,
192, 192, 0,
192, 192, 192,
255, 255, 255
]
image_data = np.array([
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 5., 5., 5., 5., 9., 9., 9., 9., 5., 5., 5., 5., 3., 3., 3., 3., 5., 5., 5., 5., 11., 11., 11., 11.],
[ 0., 0., 0., 0., 5., 5., 5., 5., 9., 9., 9., 9., 5., 5., 5., 5., 3., 3., 3., 3., 5., 5., 5., 5., 11., 11., 11., 11.],
[ 0., 0., 0., 0., 5., 5., 5., 5., 9., 9., 9., 9., 5., 5., 5., 5., 3., 3., 3., 3., 5., 5., 5., 5., 11., 11., 11., 11.],
[ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.],
[ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.],
[ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.],
[ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.],
[ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.],
[ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.],
[ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.]
], dtype=np.float64)
new_image = Image.new('P', (28, 28), color=None)
new_image.putpalette(palette_data)
new_image.putdata(image_data.astype(int))
# Resulting image data is all zeroes.
new_image.show()
new_image.save('int_data_array.png')
new_image.putdata(image_data.ravel())
# Resulting image data is all zeroes.
new_image.show()
new_image.save('float_data_sequence.png')
new_image.putdata(image_data.ravel().astype(int))
# Resulting image data is correct, as expected.
new_image.show()
new_image.save('int_data_sequence.png')Correct image:
Bad image cases:


