python - PIL 库 Image.fromarray() 导致 AttributeError : 'tuple' object has no attribute '__array_interface__'

标签 python image ubuntu python-imaging-library

我正在使用物理模拟器 pybullet,并且想要使用以下两行代码在模拟中保存来自“虚拟相机”的图像。

camera1 = pybullet.getCameraImage(900,600)
im1 = Image.fromarray(camera1[2])

第一行使用pybullet的getCameraImage函数返回未处理的图像。 camera1[2]是 RGBA 格式的像素颜色列表,每种颜色的范围为 [0..255]。
第二行应该获取该数组并将其转换为图像,然后我可以保存和查看。

当我运行代码时,我收到以下错误消息:

Traceback (most recent call last):
  File "generate_dataset.py", line 43, in <module>
    im1 = Image.fromarray(camera1[2], "RGBA")
  File "/usr/lib/python3/dist-packages/PIL/Image.py", line 2140, in 
fromarray
    arr = obj.__array_interface__
AttributeError: 'tuple' object has no attribute '__array_interface__'

代码昨天在 Ubuntu 14.04 上运行,但今天我升级到 Ubuntu 16.04,代码停止运行。我尝试使用 Python 2.7.12 和 Python 3.5.2 运行它,两个版本都会出现相同的错误。

我尝试过的事情:
添加另一行将列表转换为 numpy 数组:
camera1 = p.getCameraImage(900,600) imarray = np.asarray(camera1[2]) im1 = Image.fromarray(imarray)
结果是:

Traceback (most recent call last):
  File "generate_dataset.py", line 42, in <module>
    im1 = Image.fromarray(imarray)
  File "/usr/local/lib/python2.7/dist-packages/PIL/Image.py", line 2431, in fromarray
    raise TypeError("Cannot handle this data type")
TypeError: Cannot handle this data type

将最后一行更改为:
im1 = Image.fromarray(imarray.astype('uint8'))
结果是:

Traceback (most recent call last):
  File "generate_dataset.py", line 42, in <module>
    im1 = Image.fromarray(imarray.astype('uint8'))
  File "/usr/lib/python3/dist-packages/PIL/Image.py", line 2165, in fromarray
    size = shape[1], shape[0]
IndexError: tuple index out of range

额外信息(如果需要)

Pybullet 文档:https://docs.google.com/document/d/10sXEhzFRSnvFcl3XxNGhnD4N2SedqwdAvK3dsihxVUA/edit#heading=h.2ye70wns7io3

PIL 文档:https://pillow.readthedocs.io/en/3.1.x/reference/Image.html

我的完整代码:

import pybullet as p
import pybullet_data
import time
from PIL import Image
from random import *
import numpy as np

nExamples = 200

for n in range(0, nExamples):

  print ("Running example " + str(n))

  physicsClient = p.connect(p.DIRECT) #or p.GUI for graphical version
  p.setAdditionalSearchPath(pybullet_data.getDataPath()) #optionally
  p.setGravity(0,0,-10)
  planeId = p.loadURDF("ground.urdf")
  p.resetDebugVisualizerCamera( cameraDistance=1, cameraYaw=0, cameraPitch=-30, cameraTargetPosition=[0,0,0])

  x1 = uniform(-0.03,0.03)
  y1 = uniform(-0.03,0.03)
  x2 = x1 + uniform(-0.03,0.03)
  y2 = y1 + uniform(-0.03,0.03)
  cubeStartPos = [0.0,0,0.025]
  cubeStartPos1 = [x1,y1,0.075]
  cubeStartPos2 = [x2,y2,0.125]
  yaw0 = uniform(0,np.pi/2)
  yaw1 = uniform(0,np.pi/2)
  yaw2 = uniform(0,np.pi/2)
  cubeStartOrientation0 = p.getQuaternionFromEuler([0,0,yaw0])
  cubeStartOrientation1 = p.getQuaternionFromEuler([0,0,yaw1])
  cubeStartOrientation2 = p.getQuaternionFromEuler([0,0,yaw2])
  boxId = p.loadURDF("red_block.urdf",cubeStartPos, cubeStartOrientation0)
  boxId1 = p.loadURDF("green_block.urdf",cubeStartPos1, cubeStartOrientation1)
  boxId2 = p.loadURDF("blue_block.urdf",cubeStartPos2, cubeStartOrientation2)

  #saving the initial image...
  camera1 = p.getCameraImage(900,600)
  imarray = np.asarray(camera1[2])
  im1 = Image.fromarray(imarray.astype('uint8'))

  for i in range (250):
    p.stepSimulation()
    time.sleep(1./20.)

  camera2 = p.getCameraImage(900,600)

  #saving the image after blocks movement --> if stable this image is equal to the initial...
  im2 = Image.fromarray(camera2[2])

  #Are the images different? (Is it unstable?) --> if yes then diff is large, otherwise, diff is negligible
  diff = (camera2[2] - camera1[2]).sum()
  print("DIFFERENCE =", diff)
  if abs(diff) < 100000:
    im1.save("images/stable/image_%d.png" % n)
  else:
    im1.save("images/unstable/image_%d.png" % n)

  #cropping images
  cropped = im1.crop((350,200,550,400))
  cropped.save("images/cropped/image_%d.png" % n)

  p.disconnect()

  print ("Reached end of loop\n")

最佳答案

从您的描述中不清楚 camera1[2] 是连续 R、G、B、A 值的平面列表,还是 RGBA 元组的列表。所以我将向您展示如何阅读这两个选项。 ;)

您的主要问题是您的数据不包含宽度和高度信息,因此我们需要以某种方式提供该信息。一种方法是将数据读入正确形状的 3D Numpy 数组中。但我们也可以直接在 PIL 中使用适当的 Image 方法来完成。

在演示中,我使用 Python 循环创建一些简单的 RGBA 数据。

此脚本创建 RGBA 元组列表。

from PIL import Image

maxval = 255
width, height = 400, 300

# Display size info
size = width * height
fmt = 'Width: {}, Height: {}, Pixels: {}, Bytes: {}'
print(fmt.format(width, height, size, size * 4))

# Make a 2D gradient that starts at black in the top left corner,
# with red & green increasing horizontally, blue increasing vertically.
# This would be much faster using Numpy instead of Python loops.
pixels = []
# Make all pixels fully opaque
alpha = maxval
for y in range(height):
    blu = maxval * y // height
    for x in range(width):
        red = gre = maxval * x // width
        # Make a single RGBA pixel as a tuple
        pix = red, gre, blu, alpha
        # And save it
        pixels.append(pix)

# Show that the size of `pixels` is correct and show the first few pixels
print('Size:', len(pixels))
print(pixels[:8])

# Make a new image object. All pixels are set to black. 
img = Image.new('RGBA', (width, height))
# Copy the pixel data to the Image
img.putdata(pixels)
img.show()
img.save('test1.png') 

输出

Width: 400, Height: 300, Pixels: 120000, Bytes: 480000
Size: 120000
[(0, 0, 0, 255), (0, 0, 0, 255), (1, 1, 0, 255), (1, 1, 0, 255), (2, 2, 0, 255), (3, 3, 0, 255), (3, 3, 0, 255), (4, 4, 0, 255)]

test1.png

2D fade from black to yellow, blue, white


此脚本创建 R、G、B、A 值的平面列表。它使用 Python 3 bytes 对象,因此无法在 Python 2 上正常工作。

from PIL import Image

maxval = 255
width, height = 400, 300

# Display size info
size = width * height
fmt = 'Width: {}, Height: {}, Pixels: {}, Bytes: {}'
print(fmt.format(width, height, size, size * 4))

# Make a 2D gradient that starts at black in the top left corner,
# with red & green increasing horizontally, blue increasing vertically.
# This would be much faster using Numpy instead of Python loops.
rgba = []
# Make all pixels fully opaque
alpha = maxval
for y in range(height):
    blu = maxval * y // height
    for x in range(width):
        red = gre = maxval * x // width
        # Make a single RGBA pixel as a tuple
        pix = red, gre, blu, alpha
        # And save each of red, gre, blu, alpha to rgba. 
        # By using `.extend` we create a flat list
        rgba.extend(pix)

# Show that the size of `rgba` is correct and show the first few values.
print('Size:', len(rgba))
print(rgba[:32])

# Convert the rgba list to bytes.
rgba = bytes(rgba)
# Make a new image object from the bytes
img = Image.frombytes('RGBA', (width, height), rgba)
img.show()
img.save('test2.png')

输出

Width: 400, Height: 300, Pixels: 120000, Bytes: 480000
Size: 480000
[0, 0, 0, 255, 0, 0, 0, 255, 1, 1, 0, 255, 1, 1, 0, 255, 2, 2, 0, 255, 3, 3, 0, 255, 3, 3, 0, 255, 4, 4, 0, 255]

文件“test2.png”与“test1.png”相同。

关于python - PIL 库 Image.fromarray() 导致 AttributeError : 'tuple' object has no attribute '__array_interface__' ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50265888/

相关文章:

python - 手动计算春分和至日时,Pyephem 存在 15 分钟差异

python-3.x - CelebA 数据集无法使用 tfds.load() 访问

node.js - 在 Nodemon 运行时清除终端?

python - 在 pdb 模式下在命令提示符下键入 imshow(img) 时不显示 matplotlib 图形

python - SQLAlchemy "excluded"插入中的 PostgreSQL 命名空间...冲突

python - 从另一个目录导入类 - Python

c# - 从扫描仪捕获图像

java - 使用 SPRING MVC 在 JSP 中显示图像

r - 如何更改 sqlite 在 Ubuntu Linux R 上创建 etilqs 文件的临时文件夹?

c - 如何在Ubuntu上编译modsecurity?