我正在使用物理模拟器 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
此脚本创建 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/