2012-06-01 7 views
5

Recibo un error del siguiente código de Python3, en las líneas indicadas. x, y, y z son todas matrices numpy simples 2D idénticas pero de tamaño, y deberían funcionar igual. Sin embargo, actúan de manera diferente, con y y z chocando mientras x funciona bien.¿Qué causa AttributeError dependiente de la dimensión en la función PIL fromarray?

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 

pero esto funciona

z1 = 1*z 
imz = Image.fromarray(z1) # ok 

El error es:

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' 

Entonces, ¿qué hay de diferente entre x, y, z, z1? Nada que yo pueda decir

>>> z.dtype 
dtype('uint8') 
>>> z1.dtype 
dtype('uint8') 
>>> z.shape 
(3, 4) 
>>> z1.shape 
(3, 4) 

Estoy usando Python 3.2.3 en una máquina con Windows 7 Enterprise, con todo 64 bit.

+0

Ningún error con Python 2.7 en Ubuntu 12.04. – user545424

Respuesta

6

Puedo reproducir en ubuntu 12.04 con Python 3.2.3, numpy 1.6.1, y PIL 1.1.7-for-Python 3 en http://www.lfd.uci.edu/~gohlke/pythonlibs/#pil. La diferencia ocurre porque el array_interface de x no tiene un valor zancadas pero Y y denominaciones de origen z:

>>> x.__array_interface__['strides'] 
>>> y.__array_interface__['strides'] 
(9, 1) 
>>> z.__array_interface__['strides'] 
(9, 3) 

y así se toma una rama diferente aquí:

if strides is not None: 
    obj = obj.tobytes() 

La documentación menciona tostring, no tobytes:

# If obj is not contiguous, then the tostring method is called 
# and {@link frombuffer} is used. 

Y la fuente de Python 2 de PIL 1.1.7 utiliza tostring:

if strides is not None: 
    obj = obj.tostring() 

así que sospecho que se trata de un error introducido durante una conversión de 2 a 3 en la que se realizaron cambios str/bytes. Basta con sustituir tobytes() por tostring() en Image.py y debería funcionar:

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! 
>>> 
+1

Gracias por esto. Esto me indicó una solución, que consistía en hacer una copia de la matriz, como 'arr2 = arr.copy(); devuelve Image.fromarray (arr2, 'L') ', que funciona, aunque' .fromarray (arr, ...) 'falla. –

2

De acuerdo con el DSM. También tengo el mismo problema con PIL 1.17.

En mi caso, necesito transferir la imagen ndarray int y guardarla.

x = np.asarray(img[:, :, 0] * 255., np.uint8) 
image = Image.fromarray(x) 
image.save("%s.png" % imgname) 

Recibí errores como el tuyo.

Intenté al azar otro método: scipy.msic.imsave para guardar la imagen directamente.

scipy.msic.imsave(imgname, x) 

¡Funciona! No olvides el '.png' en el nombre de la imagen.

Cuestiones relacionadas