Reputation: 197
I have a RGB image that I split in its three channels (I also have a plot for each channel). How can I obtain a grayscale image by taking the mean across the three channels? I did
np.average(my_image)
and I get the average value back, but if I do
imshow(np.average(my_image)
I can't plot the image and actually see it (I got the error: Invalid dimensions for image data)
Upvotes: 1
Views: 7973
Reputation: 880877
To average over the last axis of my_image
, use
np.average(my_image, axis=-1)
If my_image
has shape (H, W, 3)
, then np.average(my_image, axis=-1)
will return an array of shape (H, W)
.
For example,
In [9]: my_image = np.arange(18).reshape((3,2,3))
In [10]: np.average(my_image, axis=-1)
Out[10]:
array([[ 1., 4.],
[ 7., 10.],
[ 13., 16.]])
Without axis=-1
, np.average
takes the mean over all values in the array.
In [11]: np.average(my_image)
Out[11]: 8.5
imshow
expects an array, not a float. This is why you were getting an "invalid dimension" error.
To display the array as a grayscale image using matplotlib:
In [24]: arr = np.average(my_image, axis=-1)
In [25]: plt.imshow(arr, interpolation='nearest', cmap=plt.get_cmap('gray'))
Out[25]: <matplotlib.image.AxesImage at 0xa8f01cc>
In [26]: plt.show()
To make a greyscale image using PIL:
import Image
import numpy as np
my_image = np.linspace(0, 255, 300*200*3).reshape((300,200,3))
arr = np.average(my_image, axis=-1)
img = Image.fromarray(arr.astype('uint8'))
img.save('/tmp/out.png')
Note that there are other ways to convert an RGB image to a grayscale image than by taking the mean. For instance, the luminosity is defined by
0.21 R + 0.72 G + 0.07 B
and in practice tends to produce a better result.
Upvotes: 3