How to convert a NumPy array to PIL image applying matplotlib colormap
Solution 1
Quite a busy one-liner, but here it is:
- First ensure your NumPy array,
myarray
, is normalised with the max value at1.0
. - Apply the colormap directly to
myarray
. - Rescale to the
0-255
range. - Convert to integers, using
np.uint8()
. - Use
Image.fromarray()
.
And you're done:
from PIL import Image
from matplotlib import cm
im = Image.fromarray(np.uint8(cm.gist_earth(myarray)*255))
with plt.savefig()
:
with im.save()
:
Solution 2
- input = numpy_image
- np.unit8 -> converts to integers
- convert('RGB') -> converts to RGB
Image.fromarray -> returns an image object
from PIL import Image import numpy as np PIL_image = Image.fromarray(np.uint8(numpy_image)).convert('RGB') PIL_image = Image.fromarray(numpy_image.astype('uint8'), 'RGB')
Solution 3
The method described in the accepted answer didn't work for me even after applying changes mentioned in its comments. But the below simple code worked:
import matplotlib.pyplot as plt
plt.imsave(filename, np_array, cmap='Greys')
np_array could be either a 2D array with values from 0..1 floats o2 0..255 uint8, and in that case it needs cmap. For 3D arrays, cmap will be ignored.
Related videos on Youtube

heltonbiker
I am an ex-physician, have studied mechanical engineering for a while, and have a master degree in product design. Now I work designing diagnostic equipment (surface EMG, posturography, pedobarography), dealing with system requirements, data visualization, and GUI design, and the like. I am also a die-hard cyclist, be it trails (not much nowadays), off-road, commuting, touring or randonneuring. Besides, I have deep interests in bike design and mechanics.
Updated on June 07, 2020Comments
-
heltonbiker over 3 years
I have a simple problem, but I cannot find a good solution to it.
I want to take a NumPy 2D array which represents a grayscale image, and convert it to an RGB PIL image while applying some of the matplotlib colormaps.
I can get a reasonable PNG output by using the
pyplot.figure.figimage
command:dpi = 100.0 w, h = myarray.shape[1]/dpi, myarray.shape[0]/dpi fig = plt.figure(figsize=(w,h), dpi=dpi) fig.figimage(sub, cmap=cm.gist_earth) plt.savefig('out.png')
Although I could adapt this to get what I want (probably using StringIO do get the PIL image), I wonder if there is not a simpler way to do that, since it seems to be a very natural problem of image visualization. Let's say, something like this:
colored_PIL_image = magic_function(array, cmap)
-
Adam over 6 yearsFor fully working code, you may ref: Is there any good color map to convert gray-scale image to colorful ones using python's PIL?
-
-
heltonbiker over 11 yearsThe "Apply the colormap directly to
myarray
" part cut straight to the heart! I didn't knew it was possible, thank you! -
heltonbiker over 11 yearsStudying the docs about LinearSegmentedColormap (from which cm.gist_earth is an instance), I discovered that it's possible to call it with a "bytes" argument which already converts it to uint8. Then, the one-liner gets a lot quieter:
im = Image.fromarray(cm.gist_earth(myarray, bytes=True))
-
Ciprian Tomoiagă almost 7 years@heltonbiker what shape should
myarray
have ? I'm trying to get a wider image -
heltonbiker almost 7 years@CiprianTomoiaga, the shape of the array should be the image dimensions you want. For example, a VGA image would be generated from an array with shape (1024,768). You should notice this applies for monochrome images. This is important because usually when you convert an RGB image to an array, its shape is, for example, (1024,768,3), since it has three channels.
-
Ciprian Tomoiagă almost 7 yearsAwesome! To generate a legend from a colormap I chained
repeat
andreshape
like this:legegend_arry = plt.get_cmap(cmap_name)(np.linspace(0,1,legend_h).repeat(legend_w).reshape(legend_h,legend_w), bytes=True)
. Callingfrombytes
onlegend_arry
gives a PIL image of size(legend_h, legend_w)
. Thanks for the reference ! -
rnso about 5 yearsI am getting error
NameError: name 'cm' is not defined
-
Quantum7 about 5 years@mso
from matplotlib import cm
-
Aaron over 4 yearsAlso for a different colour map use
im = Image.fromarray(np.uint8(cm.get_cmap('inferno')(myarray)*255))
-
Jaimil Patel over 3 yearsHope It will solve issue but please add explanation of your code with it so user will get perfect understanding which he/she really wants.
-
Catalina Chircu over 3 yearsGood, updated answer. The previous ones are from several years ago.
-
Hyelin almost 3 yearsIs there a reason for applying cm.gist_earth to myarray? I just thought I'd multiply 255 right away.
-
SaladHead over 2 yearsI like how this post has 256 up-votes. Tempted but can't do an up-vote.
-
El Bachir almost 2 yearsGreat solution. Used this to convert a numpy array to a PIL image inorder to display it in a Tkinter Frame.
new_image = Image.fromarray(np.uint8(image_array)) tkinter_image = ImageTk.PhotoImage(new_image)
-
bart-khalid over 1 yearworks well for me without 'RGB' arg, in order to keep the same image channel