I'm getting an error from the following Python3 code, in the indicated lines. x, y, and z are all plain 2D numpy arrays identical but for size, and ought to work the same. Yet they act differently, with y and z crashing while x works fine.
import numpy as np
from PIL import Image
a = np.ones( ( 3,3,3), dtype='uint8' )
x = a[1,:,:]
y = a[:,1,:]
z = a[:,:,1]
imx = Image.fromarray(x) # ok
imy = Image.fromarray(y) # error
imz = Image.fromarray(z) # error
but this works
z1 = 1*z
imz = Image.fromarray(z1) # ok
The error is:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python3\lib\site-packages\PIL\Image.py", line 1918, in fromarray
obj = obj.tobytes()
AttributeError: 'numpy.ndarray' object has no attribute 'tobytes'
So what's different between x, y, z, z1? Nothing that I can tell.
>>> z.dtype
dtype('uint8')
>>> z1.dtype
dtype('uint8')
>>> z.shape
(3, 4)
>>> z1.shape
(3, 4)
I'm using Python 3.2.3 on a Windows 7 Enterprise machine, with everything 64 bit.
I can reproduce on ubuntu 12.04 with Python 3.2.3, numpy 1.6.1, and PIL 1.1.7-for-Python 3 at http://www.lfd.uci.edu/~gohlke/pythonlibs/#pil. The difference happens because the array_interface of x doesn't have a strides value but y's and z's do:
>>> x.__array_interface__['strides']
>>> y.__array_interface__['strides']
(9, 1)
>>> z.__array_interface__['strides']
(9, 3)
and so a different branch is taken here:
if strides is not None:
obj = obj.tobytes()
The documentation mentions tostring
, not tobytes
:
# If obj is not contiguous, then the tostring method is called
# and {@link frombuffer} is used.
And the Python 2 source of PIL 1.1.7 uses tostring
:
if strides is not None:
obj = obj.tostring()
so I suspect that this was an error introduced during a 2-to-3 conversion in which str/bytes changes were made. Simply replace tobytes()
by tostring()
in Image.py
and it should work:
Python 3.2.3 (default, May 3 2012, 15:54:42)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> from PIL import Image
>>>
>>> a = np.ones( ( 3,3,3), dtype='uint8' )
>>> x = a[1,:,:]
>>> y = a[:,1,:]
>>> z = a[:,:,1]
>>>
>>> imx = Image.fromarray(x) # ok
>>> imy = Image.fromarray(y) # now no error!
>>> imz = Image.fromarray(z) # now no error!
>>>
Agree with DSM. I also got the same problem with PIL 1.17.
In my case, I need transfer the ndarray int image and save it.
x = np.asarray(img[:, :, 0] * 255., np.uint8)
image = Image.fromarray(x)
image.save("%s.png" % imgname)
I got errors just like yours.
I randomly tried other method: scipy.msic.imsave to save the image directly.
scipy.msic.imsave(imgname, x)
It works! Don't forget the '.png' in the imagename.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With