如何使用matplotlib colormap将NumPy数组转换为PIL图像

273

我有一个简单的问题,但是我找不到一个好的解决方案。

我想要将表示灰度图像的NumPy 2D数组转换为RGB PIL图像,并应用一些matplotlib颜色映射。

我可以使用pyplot.figure.figimage命令获得合理的PNG输出:

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')
尽管我可以适应这种方式来获得我想要的结果(可能使用StringIO来获取PIL图像),但我想知道是否有更简单的方法来解决这个问题,因为它似乎是图像可视化的一个非常自然的问题。假设有这样一种方式:
colored_PIL_image = magic_function(array, cmap)

3个回答

378

这是一个相当繁忙的一行代码,但是下面就是它:

  1. 首先确保你的NumPy数组 myarray 是规范化的,最大值为 1.0
  2. 直接将颜色映射应用于 myarray
  3. 将数据重新缩放到 0-255 的范围内。
  4. 使用 np.uint8() 转换成整数。
  5. 使用 Image.fromarray()

然后你就完成了:

from PIL import Image
from matplotlib import cm
im = Image.fromarray(np.uint8(cm.gist_earth(myarray)*255))

使用plt.savefig():

在此输入图像描述

使用im.save():

在此输入图像描述


10
“将颜色映射直接应用于myarray”一节真正抓住了重点!我不知道这是可能的,谢谢! - heltonbiker
46
阅读有关LinearSegmentedColormap的文档(其中cm.gist_earth是一个实例),我发现可以使用“bytes”参数调用它,这将自动将其转换为uint8。然后,一行代码就会更加安静:im = Image.fromarray(cm.gist_earth(myarray, bytes=True)) - heltonbiker
2
@CiprianTomoiaga,数组的形状应该是你想要的图像尺寸。例如,VGA图像将从形状为(1024,768)的数组生成。您应该注意,这适用于单色图像。这很重要,因为通常当您将RGB图像转换为数组时,其形状为(1024,768,3),因为它有三个通道。 - heltonbiker
7
我遇到了错误 NameError: name 'cm' is not defined - rnso
11
@mso 从matplotlib导入cm - Quantum7
显示剩余6条评论

84
  • input = numpy_image

  • np.uint8 -> 转换为整数

  • convert('RGB') -> 转换为RGB

  • Image.fromarray -> 返回图像对象

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

7
希望您的代码可以解决问题,但请在其中添加说明,以使用户能够获得完美的理解。 - Jaimil Patel
4
好的,更新的答案。之前的回答是几年前的。 - Catalina Chircu
2
对我来说,不带“RGB”参数可以很好地工作,以保持相同的图像通道。 - bart-khalid

12

尽管我已经按照接受的答案评论中提到的更改进行了操作,但该方法对我没有起作用。但是以下简单代码有效:

import matplotlib.pyplot as plt
plt.imsave(filename, np_array, cmap='Greys')

np_array可以是一个具有0到1浮点数或0到255 uint8的值的二维数组,在这种情况下,它需要cmap。对于三维数组,将忽略cmap。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接