将Numpy数组保存为图像

422

我有一个Numpy数组类型的矩阵。如何将它写入磁盘作为图像?任何格式都可以(png,jpeg,bmp ...)。一个重要的限制是PIL不存在。


18
我只想指出下面的一些答案,以及肯定有一些人找到这个问题,不符合上面列出的“没有”PIL的限制。由于一些提问者和一些回答都避免了这个限制,所以我鼓励任何在这里并且不介意使用PIL的人向下查看,任何非PIL的答案(新的或旧的)都要说明它们是使用PIL的类型的答案,以区别于符合原始约束条件的答案。 - lindes
似乎相关:https://dev59.com/t1wX5IYBdhLWcg3wtBXG - hola
24个回答

445
使用PIL,通过以下方式保存NumPy数组arr
from PIL import Image
im = Image.fromarray(arr)
im.save("your_file.jpeg")

请查看文档以了解可用数据格式,包括JPEG、PNG等等。

5
图像是PIL模块的一部分。执行 "print Image.file" 命令即可。 - Juh_
21
对于那些来到这里并且拥有 PIL 库的人来说,这篇文章非常有帮助——我认为我会使用 from PIL import Image 来使它更加清晰明了。 - sage
6
如果你有一张RGB图像,你可以使用im = Image.fromarray(A).convert('RGB')来获取该图像。 更多信息请参考:https://dev59.com/Xm445IYBdhLWcg3wwc2g - Roger Veciana
使用 uint8 数组的第三个轴来编码 RGB 可以使用这种方法。可以使用 "pip install pillow" 安装 PIL 模块。 - bli
1
@Ludovico Verniani 它不会扭曲图像,但它使用的颜色编码有些不寻常,它的颜色顺序是BGR而不是RGB。 - Zvika
显示剩余7条评论

273

这个使用了PIL,但或许对一些人会有用:

import scipy.misc
scipy.misc.imsave('outfile.jpg', image_array)

编辑:当前的scipy版本开始对所有图像进行规范化处理,以便使min(data)成为黑色,max(data)成为白色。如果数据应该是精确的灰度级别或精确的RGB通道,则这是不需要的。解决方案:

import scipy.misc
scipy.misc.toimage(image_array, cmin=0.0, cmax=...).save('outfile.jpg')

20
imsave位于.../scipy/misc/pilutil.py中,它使用PIL。 - denis
6
转换为JPG格式时要小心,因为它是一种有损压缩格式,所以您可能无法恢复用于生成图像的精确数据。 - Feanil
9
这在scipy 0.19中已被弃用,请使用scipy.io.imwrite。 - g.stevo
7
"imsave在SciPy 1.0.0中已被弃用,并将在1.2.0中被移除。" (Scipy 1.1.0文档) - noobar
33
scipy.misc.imsave已经弃用。使用import imageio; imageio.imwrite('file_name.jpg', nmupy_array)代替。 - ChaosPredictor
显示剩余9条评论

133

使用 matplotlib

import matplotlib.image

matplotlib.image.imsave('name.png', array)

适用于matplotlib 1.3.1,我不知道低版本是否适用。来自文档字符串:

Arguments:
  *fname*:
    A string containing a path to a filename, or a Python file-like object.
    If *format* is *None* and *fname* is a string, the output
    format is deduced from the extension of the filename.
  *arr*:
    An MxN (luminance), MxNx3 (RGB) or MxNx4 (RGBA) array.

在此输入图片描述


使用这个。但是遭受内存泄漏的困扰。 - SolessChong
在新版本中的matplotlib.imsave() - Vinay Lodha
9
在 matplotlib 2+ 中,matplotlib.pyplot.imsave 可以实现图像的保存。 - Aleksei Petrenko
这是对我有效的方法 :) (其他所有内容都需要PIL,而它只适用于Python 2) - Hugh Perkins
1
@HughPerkins 尝试在Python 3中使用Pillow替代PIL。 - christianbrodbeck
21
导入 matplotlib.pyplot 库:import matplotlib.pyplot as plt,然后使用 plt.imsave('name.png', array) 将数组(array)保存为名为 'name.png' 的图片。 - Alessandro Jacopson

92

有Python的opencv文档在这里)。

import cv2
import numpy as np

img = ... # Your image as a numpy array 

cv2.imwrite("filename.png", img)

如果您需要进行除保存以外的更多处理,这将非常有用。


1
为什么数组大小是10?在这个解决方案中,选择使用10的原因是什么? - Gathide
6
这是一个写入任意numpy矩阵到文件的例子。在实际应用中,将np.zeros((10,10))替换为您的图像。 - ButterDog
5
我该如何在使用cv2保存图像时添加类似于“cmap =“gray”的内容? - Mona Jalal
@Xocoatzin 链接失效了吗? - jtlz2
1
@jtlz2 已更新链接。 - ButterDog
@MonaJalal 我有同样的问题,你找到解决方案了吗? - Sundeep Pidugu

82

纯Python(2和3),一个没有第三方依赖的代码片段。

该函数编写了压缩的,真彩色(每像素4个字节)RGBA PNG图像。

def write_png(buf, width, height):
    """ buf: must be bytes or a bytearray in Python3.x,
        a regular string in Python2.x.
    """
    import zlib, struct

    # reverse the vertical line order and add null bytes at the start
    width_byte_4 = width * 4
    raw_data = b''.join(
        b'\x00' + buf[span:span + width_byte_4]
        for span in range((height - 1) * width_byte_4, -1, - width_byte_4)
    )

    def png_pack(png_tag, data):
        chunk_head = png_tag + data
        return (struct.pack("!I", len(data)) +
                chunk_head +
                struct.pack("!I", 0xFFFFFFFF & zlib.crc32(chunk_head)))

    return b''.join([
        b'\x89PNG\r\n\x1a\n',
        png_pack(b'IHDR', struct.pack("!2I5B", width, height, 8, 6, 0, 0, 0)),
        png_pack(b'IDAT', zlib.compress(raw_data, 9)),
        png_pack(b'IEND', b'')])

...数据应该直接写入二进制文件,例如:

data = write_png(buf, 64, 64)
with open("my_image.png", 'wb') as fh:
    fh.write(data)


2
这似乎正是我要找的,但你能加一些注释吗?我不明白它如何写入文件。你需要将输出写入先前打开的文件中吗?谢谢! - PhilMacKay
1
@PhilMacKay,数据只需写入二进制文件。已添加注释。 - ideasman42
1
有人能指定图像(buf)应该是什么格式吗?它似乎不是一个numpy数组... - christianbrodbeck
1
@christianmbrodbeck,一个字节数组(RGBARGBA...) - ideasman42
1
感谢@ideasman42。我将这段代码移植到了Blender中 - emackey
1
请澄清一下:这段代码片段附带了GPL许可证吗?(我对原始来源的理解。) - penguineer

66
你可以使用PyPNG。它是一个纯Python(无依赖)的开源PNG编码器/解码器,同时支持将NumPy数组写入图像。

6
记得将值按照 PNG 的正确范围进行缩放,通常为 0 到 255。神经网络中的值范围通常为 0 到 1 或 -1 到 1。 - Tomáš Gavenčiak
15
PyPNG是纯Python编写的,这减少了它的外部依赖,但也导致它比PIL及其派生类慢得多。例如,在我的电脑上保存一张3000x4000像素的图片使用PyPNG需要4.05秒,而使用scipy.misc.imsave只需要0.59秒(快了6倍)。 - Zvika
1
@TomášGavenčiak - scipy.misc.imsave在较新版本的Scipy中已被弃用。下面有几个替代方案,可以使用imageio.imwrite('image_file.jpg', array)。 - Psi-Ed

30
如果你有matplotlib,你可以这样做:
import matplotlib.pyplot as plt
plt.imshow(matrix) #Needs to be in row,col order
plt.savefig(filename)
这将保存图表(而不是图像本身)。 在此输入图片描述

11
对于pyplot接口,plt.figure()函数是多余的。此外,只有在想要查看图形窗口时才需要plt.show()函数--在这种情况下,只需保存图像文件,因此无需调用show()函数。 - DopplerShift
7
请注意,生成的图像文件将包含 matplotlib 图形的轴和灰色区域 -- 不仅仅是像素数据。 - Dave
1
如果您在远程主机上运行脚本并通过SSH连接,但没有图形界面支持,则无法正常工作。 - Temak
如果您想在笔记本中显示图像,可以添加以下内容:>>“from IPython.display import Image”,然后>>“Image(filename=filename)” - Robert
去除坐标轴:plt.axis('off') - yakout
显示剩余2条评论

30

保存numpy数组为图像,您有几个选择:

1)最佳选择:OpenCV

 import cv2   
 cv2.imwrite('file name with extension(like .jpg)', numpy_array)

2) Matplotlib

  from matplotlib import pyplot as plt
  plt.imsave('file name with extension(like .jpg)', numpy_array)

3) PIL

  from PIL import Image
  image = Image.fromarray(numpy_array)
  image.save('file name with extension(like .jpg)')

4) ...


1
在加载模块所需的时间方面,“from PIL import Image” 明显是最佳选择。 - Íhor Mé

21

scipy.misc给出有关imsave函数的弃用警告,并建议改用imageio

import imageio
imageio.imwrite('image_name.png', img)

18
你可以在Python中使用'skimage'库。
示例:
from skimage.io import imsave
imsave('Path_to_your_folder/File_name.jpg',your_array)

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