giulia_dnt
giulia_dnt

Reputation: 197

average grayscale from rgb image in python

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

Answers (1)

unutbu
unutbu

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()

enter image description here


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')

enter image description here


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

Related Questions