title: PIL library Image.fromarray() causes AttributeError: 'tuple' object has no attribute '__array_interface__'
body: <p>I'm using the physics simulator pybullet, and want to save an image from a 'virtual camera' within my simulation, using the following two lines of code.</p>
  
  <pre><code>camera1 = pybullet.getCameraImage(900,600)
  im1 = Image.fromarray(camera1[2])
  </code></pre>
  
  <p>The first line uses pybullet's getCameraImage function to return an unprocessed image. <code>camera1[2]</code> is a list of pixel colors in RGBA format, in range [0..255] for each color.<br>
  The second line <em>should</em> take that array and convert it into an image which I can then save and view.</p>
  
  <p>When I run the code I get the following error message:  </p>
  
  <pre><code>Traceback (most recent call last):
    File "generate_dataset.py", line 43, in &lt;module&gt;
      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__'
  </code></pre>
  
  <p>The code was working yesterday on Ubuntu 14.04, but today I upgraded to Ubuntu 16.04 and the code has stopped working. I have tried running it with Python 2.7.12 and Python 3.5.2, both versions get the same error.</p>
  
  <p><strong>Things I have tried:</strong><br>
  Adding another line to convert the list into a numpy array:<br>
  <code>camera1 = p.getCameraImage(900,600)
  imarray = np.asarray(camera1[2])
  im1 = Image.fromarray(imarray)</code><br>
  Resulted in:  </p>
  
  <pre><code>Traceback (most recent call last):
    File "generate_dataset.py", line 42, in &lt;module&gt;
      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
  </code></pre>
  
  <p>Changing the last line to:<br>
  <code>im1 = Image.fromarray(imarray.astype('uint8'))</code><br>
  Resulted in:  </p>
  
  <pre><code>Traceback (most recent call last):
    File "generate_dataset.py", line 42, in &lt;module&gt;
      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
  </code></pre>
  
  <p><strong>Extra info, if needed</strong></p>
  
  <p>Pybullet documentation: <a href="https://docs.google.com/document/d/10sXEhzFRSnvFcl3XxNGhnD4N2SedqwdAvK3dsihxVUA/edit#heading=h.2ye70wns7io3" rel="nofollow noreferrer">https://docs.google.com/document/d/10sXEhzFRSnvFcl3XxNGhnD4N2SedqwdAvK3dsihxVUA/edit#heading=h.2ye70wns7io3</a></p>
  
  <p>PIL documentation: <a href="https://pillow.readthedocs.io/en/3.1.x/reference/Image.html" rel="nofollow noreferrer">https://pillow.readthedocs.io/en/3.1.x/reference/Image.html</a></p>
  
  <p>My full code:  </p>
  
  <pre><code>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 --&gt; if stable this image is equal to the initial...
    im2 = Image.fromarray(camera2[2])
  
    #Are the images different? (Is it unstable?) --&gt; if yes then diff is large, otherwise, diff is negligible
    diff = (camera2[2] - camera1[2]).sum()
    print("DIFFERENCE =", diff)
    if abs(diff) &lt; 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")
  </code></pre>