8

Currently I'm using PIL and NumPy. I have a colored png image and I want to:

  1. Read it in in grayscale
  2. Convert to NumPy array
  3. Perform a FFT on array
  4. Display the image

This is what I'm trying (in IPython w/ --pylab flag):

In [1]: import Image

In [2]: img = Image.open('ping.png').convert('LA')

In [3]: img_as_np = np.asarray(img)

In [4]: img_as_np
Out[4]: array(<Image.Image image mode=LA size=1000x1000 at 0x105802950>, dtype=object)

In [5]: img_fft = fft.fft2(img_as_np) // IndexError: index out of range for array
adelbertc
  • 7,270
  • 11
  • 47
  • 70
  • Any reason for using the `LA` mode (grayscale with alpha) ? – mmgp Jan 29 '13 at 13:46
  • 1
    After you reconsider that, the answer at http://stackoverflow.com/a/14472089/1832154 shows how to properly display the result of a Fourier transform. – mmgp Jan 29 '13 at 13:48
  • I read somewhere that `LA` mode will let me use `imshow()` in grayscale, I now realize `L` puts it in grayscale as well but I just need to add an argument to `imshow()` to make sure it shows up properly as grayscale. I learned (from answers below) `A` is preventing the conversion from happening properly.. my mistake :-) Thanks! – adelbertc Jan 29 '13 at 18:01

3 Answers3

5

You want to use the mode 'L' instead of 'LA' as the parameter to the convert() method. 'LA' leaves an alpha channel and then the numpy.asarray doesn't work as you intended. If you need the alpha channel, then you will need a different method to convert to a numpy array. Otherwise, use mode 'L'.

Justin Peel
  • 46,722
  • 6
  • 58
  • 80
4

It looks like you're using a version of PIL prior to 1.1.6, where they introduced the methods so that numpy would know what to do with an Image. So you're just getting img_as_np as a one-element array containing an Image object (which is what Out[4] is showing you).

You instead need to do something like np.asarray(img.getdata()), which will give you a num_pixels x num_channels array of integers between 0 and 255 (at least for the png I tried). You may want to do

img_as_np = np.asarray(img.getdata()).reshape(img.size[1], img.size[0], -1)

to lay it out like the image (transposed). You might also want to divide by 255 to get float values between 0 and 1, if that's the format you're expecting (as does e.g. matplotlib's imshow).

Danica
  • 28,423
  • 6
  • 90
  • 122
2

Using this for an image:

>>> from PIL import Image
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> Image.__version__
'1.1.7'
>>> img = Image.open('lena.png').convert('L')
>>> data = np.asarray(img.getdata()).reshape(img.size)
>>> fft = np.fft.fft2(data)
>>> fft[0, 0] = 0 # remove DC component for visualization
>>> plt.imshow(np.abs(np.fft.fftshift(fft)), interpolation='nearest')
<matplotlib.image.AxesImage object at 0x046012F0>
>>> plt.show()
>>> plt.imshow(np.abs(np.fft.fftshift(fft))[224:288, 224:288], interpolation='nearest')
<matplotlib.image.AxesImage object at 0x0476ED70>
>>> plt.show()

enter image description here

Jaime
  • 65,696
  • 17
  • 124
  • 159