VanSpoof VanSpoof - 6 months ago 31
Python Question

python, numpy: Setting the values for an entire 2D plane of a 3D array

I would like to store the pixel brightness values of several images in a 3D array, but am unsure how to set the values of an entire 'plane' of the 3D 'cube' in one go. Here's my attempt:

imag = Image.open(imagArray[i])
imagPix[:,:,i] = self.getPixelValues(imag)


imagArray is an array of filepaths for images stored on the local computer and imagPix is the 3D array of pixel values. imagPix is initially defined as:

imagPix = np.zeros((width, height, lenImagArray))


where width and height are the dimensions of the image and lenImagArray is the number of images to be saved in the array (in this case 3). I have tried the imagPix[:,:,i] line with '0:' and ':' operators to no avail.

The specific error I receive is:

ValueError: could not broadcast input array from shape (640, 480, 3) into shape (640, 480)


The getPixelValues method returns a 2D array of pixel brightness values. Code for this is below:

def getPixelValues(self, pixImg): ## pixImg is the location of the image, not the image itself
## open image and convert to rgb
imag = Image.open(str(pixImg))
imag = imag.convert('RGB')

## get size of image
width, height = imag.size

pixData = list(imag.getdata())
pixData = [pixData[i * width:(i+1) * width] for i in xrange(height)]
## close image and return pixel array
imag.close()
return pixData


Do I have to use a for loop instead of setting all the values in one go?
Thanks in advance. :)

EDIT:

Now that my problems with getdata() returning a tuple have been fixed I've run into a new problem when using numpy.mean():

pixData = np.array(imag.getdata())
pixData = [pixData[i * width:(i+1) * width] for i in xrange(height)]
pixData = np.mean(pixData, 2)


This give me the error:

ValueError: could not broadcast input array from shape (480, 640) into shape (640, 480)

So the dimensions of my array have been 'rotated' for no discernible reason.

Answer

You are actually trying to assign a 3-dimensional array to a 2-dimensional slice. What happens is:

  • imag.getdata() returns a sequence of pixel values. Those pixel values are actually (R,G,B) tuples.
  • So list(imag.getdata()) is a list of tuples.
  • So pixData after the manipulation inside getPixelValues is a list of lists of tuples.
  • So when you try to assign this to a numpy array slice, it's treated as a 3-dimensional array.

What you need to do about this will depend on what you actually want to happen. As it stands, your imagPix array is clearly intended to be a 3-dimensional stack of 2-dimensional (greyscale) images. So you could convert your 3-dimensional image to 2 dimensions in some appropriate way. (It might be enough just to pull out one slice of it, or you might want to take some sort of weighted average of the colour planes, or something.)

Alternatively, perhaps you actually want imagPix to be a 4-dimensional stack of 3-dimensional images.

Or perhaps whatever process creates those images should be creating explicitly-greyscale ones, and getPixelValues shouldn't be converting them to RGB at all.

Comments