为什么 `imshow` 以彩色显示 2D(非 RGB)数组,我如何将这样的彩色图像导出到 .png 文件?
Why does `imshow` display a 2D (non-RGB) array in color, and how can I export such a color image to a .png file?
我生成了一个 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 似乎不是一个可行的选择,因为分辨率太差了。
当您将二维数组传递给 plt.imshow
时,强度值会映射到 RGBA 值。这是根据称为颜色图的查找 table 完成的,可以通过 cmap=
关键字参数指定。例如,要以灰度方式绘制 Mandelbrot 数组,您可以 select 'gray'
颜色图:
plt.imshow(arr, cmap='gray')
如果您不传递 cmap=
参数,matplotlib 将使用任何默认值,您也可以在 matplotlibrc
文件中对其进行修改。对于当前版本的 matplotlib 的全新安装,默认是一个名为 'jet'
的颜色图,如下所示:
'jet'
is a pretty terrible colormap for many purposes, and will soon be replaced as the default colormap in matplotlib v2.0. You can read more about selecting colormaps in the official documentation.
您还可以将 3D 数组传递给 imshow
,其中最终维度的大小为 3 或 4。在这种情况下,最终维度被解释为每个像素的 RGB(A) 值.由于颜色信息已包含在数组中,因此不需要查找 table,因此 cmap=
参数将被忽略。
要解决问题的第二部分,将数组保存为彩色全分辨率 .png
图像的一种简单方法是使用 plt.imsave
,这也需要 cmap=
参数:
plt.imsave('mandelbrot.png', arr, cmap='jet')
plt.imsave
仅导出数组中的原始像素,因此 10000x10000 输入数组将生成一个 .png
恰好 10000x10000 像素的图像。
相比之下,plt.savefig
渲染整个图形 canvas(包括边距、轴、其他绘图元素等),并根据 (1) 中图形的大小进行缩放英寸和 (2) dpi=
关键字参数。虽然您可以通过将 DPI 设置得比您需要的大得多来获得足够高的分辨率,但是使用这种方法以实际大小渲染您的数组会困难得多,因为您需要 fiddle图形大小 and/or DPI,以及轴的位置和大小等
正如我在上面的评论中提到的,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)
我无法 post 原始 PNG(大约 200 兆字节),但这可以为您提供所需的详细信息。上面脚本输出的一些放大截图:
请注意,这样图(包括边框、轴标签等)为 10000x10000 像素,因此您仍然看不到来自 arr
的实际 10000x10000 像素。 ali_m 和 imsave
的解决方案确实解决了这个问题,如果您不介意没有轴标签、标题等。
我生成了一个 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 似乎不是一个可行的选择,因为分辨率太差了。
当您将二维数组传递给 plt.imshow
时,强度值会映射到 RGBA 值。这是根据称为颜色图的查找 table 完成的,可以通过 cmap=
关键字参数指定。例如,要以灰度方式绘制 Mandelbrot 数组,您可以 select 'gray'
颜色图:
plt.imshow(arr, cmap='gray')
如果您不传递 cmap=
参数,matplotlib 将使用任何默认值,您也可以在 matplotlibrc
文件中对其进行修改。对于当前版本的 matplotlib 的全新安装,默认是一个名为 'jet'
的颜色图,如下所示:
'jet'
is a pretty terrible colormap for many purposes, and will soon be replaced as the default colormap in matplotlib v2.0. You can read more about selecting colormaps in the official documentation.
您还可以将 3D 数组传递给 imshow
,其中最终维度的大小为 3 或 4。在这种情况下,最终维度被解释为每个像素的 RGB(A) 值.由于颜色信息已包含在数组中,因此不需要查找 table,因此 cmap=
参数将被忽略。
要解决问题的第二部分,将数组保存为彩色全分辨率 .png
图像的一种简单方法是使用 plt.imsave
,这也需要 cmap=
参数:
plt.imsave('mandelbrot.png', arr, cmap='jet')
plt.imsave
仅导出数组中的原始像素,因此 10000x10000 输入数组将生成一个 .png
恰好 10000x10000 像素的图像。
相比之下,plt.savefig
渲染整个图形 canvas(包括边距、轴、其他绘图元素等),并根据 (1) 中图形的大小进行缩放英寸和 (2) dpi=
关键字参数。虽然您可以通过将 DPI 设置得比您需要的大得多来获得足够高的分辨率,但是使用这种方法以实际大小渲染您的数组会困难得多,因为您需要 fiddle图形大小 and/or DPI,以及轴的位置和大小等
正如我在上面的评论中提到的,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)
我无法 post 原始 PNG(大约 200 兆字节),但这可以为您提供所需的详细信息。上面脚本输出的一些放大截图:
请注意,这样图(包括边框、轴标签等)为 10000x10000 像素,因此您仍然看不到来自 arr
的实际 10000x10000 像素。 ali_m 和 imsave
的解决方案确实解决了这个问题,如果您不介意没有轴标签、标题等。