【问题标题】:Why does `imshow` display a 2D (non-RGB) array in color, and how can I export such a color image to a .png file?为什么 `imshow` 会以彩色显示 2D(非 RGB)数组,如何将这样的彩色图像导出到 .png 文件?
【发布时间】:2016-02-12 22:58:18
【问题描述】:

我生成了一个 Mandelbrot 图形作为 10000x10000 像素的 numpy 数组:

[[ 100.  100.  100. ...,   12.   12.   13.]
 [ 100.  100.  100. ...,   12.   13.   14.]
 [ 100.  100.  100. ...,   12.   12.   14.]
 ..., 
 [   3.    3.    3. ...,    3.    3.    3.]
 [   3.    3.    3. ...,    3.    3.    3.]
 [   3.    3.    3. ...,    3.    3.    3.]]

如果我使用 matplotlib 显示数组:

arr = np.zeros((10000, 10000)) # my array
import matplotlib.pyplot at plt
plt.imshow(arr)
plt.show()

我得到了一张非常漂亮的彩色图像。

但是为什么

除此之外,如果我尝试将其导出到.png,我会得到一个黑白图像:

import PIL.Image as im
iimg = im.fromarray(arr)
iimg = iimg.convert("RGB") # std was "F", but it didn't work
iimg.save("img_mandelbrot.png")

有没有办法将这样的彩色图像导出为 png? matplotlib 似乎不是一个可行的选择,因为分辨率太差了。

【问题讨论】:

  • 您可能想澄清您的问题。大多数 matplotlib 2D 绘图例程返回非常漂亮的彩色图像 :) imshow 也是如此;除非您为每个点提供实际颜色(MxNx3 [RGB] 或 MxNx4 [RGBA]),否则二维数组会根据数组的值进行简单着色。
  • here
  • @julbra 查看我的编辑。
  • 为什么 matplotlib 的分辨率“太差”? savefig() 有一个 dpi 关键字,因此将图形大小与正确的 dpi 相结合,您可以尽可能详细地保存它吗?
  • @julbra 谢谢你,我没有想到这个,(我使用的是matplotlib.pyplot.imsave),提供它作为答案

标签: python image numpy matplotlib python-imaging-library


【解决方案1】:

当您将二维数组传递给plt.imshow 时,强度值将映射到 RGBA 值。这是根据称为颜色图的查找表完成的,可以通过cmap= 关键字参数指定。例如,要以灰度绘制 Mandelbrot 数组,您可以选择 'gray' 颜色图:

plt.imshow(arr, cmap='gray')

如果您不传递 cmap= 参数,matplotlib 将使用默认值,您也可以在 matplotlibrc 文件中进行修改。对于当前版本的 matplotlib 的全新安装,默认是一个名为 'jet' 的颜色图,如下所示:

'jet' is a pretty terrible colormap for many purposeswill soon be replaced as the default colormap in matplotlib v2.0。您可以在official documentation 中阅读有关选择颜色图的更多信息。

您还可以将 3D 数组传递给 imshow,其中最终维度的大小为 3 或 4。在这种情况下,最终维度被解释为每个像素的 RGB(A) 值。由于颜色信息已经包含在数组中,因此不需要查找表,因此cmap= 参数将被忽略。


为了解决您问题的第二部分,将您的数组保存为彩色映射的全分辨率.png 图像的一种简单方法是使用plt.imsave,它也需要一个cmap= 参数:

plt.imsave('mandelbrot.png', arr, cmap='jet')

plt.imsave 只是导出数组中的原始像素,因此一个 10000x10000 的输入数组将生成一个正好为 10000x10000 像素的.png 图像。

相比之下,plt.savefig 渲染整个图形画布(包括边距、轴、其他绘图元素等),并根据 (1) 以英寸为单位的图形大小和 (2) @987654346 进行缩放@ 关键字参数。虽然您可以通过将 DPI 设置为比您需要的大得多来获得足够高的分辨率,但使用此方法以实际大小渲染数组会困难得多,因为您需要摆弄图形大小和/或DPI,以及轴的位置和大小等。

【讨论】:

  • 谢谢! (我会等待 jubra 摆出回答接受她的回答)。
【解决方案2】:

正如我在上面的评论中提到的,savefig 有一个 dpi 选项

例如:

import numpy as np
import matplotlib.pyplot as plt

plt.figure(figsize=(10,10)) #
arr = np.random.random((10000,10000)) # my array
plt.imshow(arr)

plt.savefig('fig.png', dpi=1000)

我无法发布原始 PNG(大约 200 兆字节),但这可以为您提供尽可能多的详细信息。上面脚本输出的一些放大截图:

请注意,这样的图形(包括边框、轴标签等)为 10000x10000 像素,因此您仍然看不到来自 arr 的实际 10000x10000 像素。如果您不介意没有轴标签、标题等,来自 ali_m 的 imsave 解决方案确实可以解决这个问题。

【讨论】:

    猜你喜欢
    • 2017-12-07
    • 2015-09-26
    • 2012-07-26
    • 2019-09-17
    • 2013-10-21
    • 1970-01-01
    • 1970-01-01
    • 2019-07-21
    • 1970-01-01
    相关资源
    最近更新 更多