将 Numpy 数组保存为图像
Posted
技术标签:
【中文标题】将 Numpy 数组保存为图像【英文标题】:Saving a Numpy array as an image 【发布时间】:2010-10-28 12:21:29 【问题描述】:我有一个 Numpy 数组类型的矩阵。我如何将它作为图像写入磁盘?任何格式都有效(png、jpeg、bmp...)。一个重要的限制是不存在 PIL。
【问题讨论】:
我只想指出,下面的一些答案,当然还有一些人来发现这个问题,不符合上面列出的没有的限制>PIL。由于一些提问者和一些答案都避免了这种限制,我鼓励任何在这里并且不介意 PIL 看下面的人,以及任何非 PIL 答案(新的或旧的)提到他们是 PIL-is-used答案类型,以区别于满足原始约束的答案。 似乎相关:***.com/questions/33480297/viewing-npy-images 【参考方案1】:您可以使用PyPNG。它是一个纯 Python(无依赖)开源 PNG 编码器/解码器,它 supports 将 NumPy 数组写入图像。
【讨论】:
记得将值缩放到适合 PNG 的范围,通常是 0..255。神经网络中的取值范围通常是 0..1 或 -1..1。 PyPNG 是纯 Python,它减少了它的外部依赖,但比 PIL 及其派生类慢得多。例如,使用 PyPNG 在我的机器上保存 3000x4000 图像需要 4.05 秒,但使用 scipy.misc.imsave 只需 0.59 秒(快 6 倍)。 @TomášGavenčiak - scipy.misc.imsave 现在在新版本的 Scipy 中已弃用。下面几个 cmets 的替代方法是使用 imageio.imwrite('image_file.jpg', array)【参考方案2】:如果你有 matplotlib,你可以这样做:
import matplotlib.pyplot as plt
plt.imshow(matrix) #Needs to be in row,col order
plt.savefig(filename)
这将保存绘图(而不是图像本身)。
【讨论】:
不,对于pyplot接口,plt.figure()是多余的。此外,如果您还想查看图形窗口,则只需要 plt.show() ——在这种情况下,只需要保存图像文件,因此无需调用 show()。 请注意,生成的图像文件将包含 matlplotlib 图形的轴和灰色区域——而不仅仅是像素数据。 如果你在远程主机上运行你的脚本,在没有图形界面支持的情况下通过 ssh-ing 到它,将无法工作。 如果要在笔记本中显示图像,可以添加以下内容:>>"from IPython.display import Image" 然后 >>"Image(filename=filename)" 移除轴:plt.axis('off')
【参考方案3】:
matplotlib svn 有一个新功能,可以将图像保存为图像——没有轴等。如果你不想安装 svn(直接从 matplotlib svn 中的 image.py 复制),它也是一个非常简单的向后移植功能,为简洁起见删除了文档字符串):
def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None, origin=None):
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
fig = Figure(figsize=arr.shape[::-1], dpi=1, frameon=False)
canvas = FigureCanvas(fig)
fig.figimage(arr, cmap=cmap, vmin=vmin, vmax=vmax, origin=origin)
fig.savefig(fname, dpi=1, format=format)
【讨论】:
【参考方案4】:这使用了 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')
【讨论】:
imsave 位于使用 PIL 的 .../scipy/misc/pilutil.py 中 转换为 jpg 时要小心,因为它有损,因此您可能无法恢复用于生成图像的确切数据。 现在在 scipy 0.19 使用中已弃用 - scipy.io.imwrite "imsave 在 SciPy 1.0.0 中已弃用,将在 1.2.0 中删除" (Scipy 1.1.0 doc) scipy.misc.imsave 已弃用。使用导入图像; imageio.imwrite('file_name.jpg', nmupy_array)【参考方案5】:使用PIL 的答案(以防万一有用)。
给定一个 numpy 数组“A”:
from PIL import Image
im = Image.fromarray(A)
im.save("your_file.jpeg")
您可以用几乎任何您想要的格式替换“jpeg”。有关格式的更多详细信息here
【讨论】:
Image 是 PIL 的一个模块。执行“打印 Image.__file__” 对我们这些在这里闲逛并且确实有 PIL 的人非常有帮助 - 我想我会使用from PIL import Image
来保持清楚......
如果你有一个 RGB 图像,你可以使用 im = Image.fromarray(A).convert('RGB') 获取图像更多信息:***.com/questions/4711880/…
使用 uint8 数组的第三轴对 RGB 进行编码可以使用此方法。可以使用“pip install枕头”安装模块PIL。
@Ludovico Verniani 它不会扭曲图像,但它确实使用了一种不太常见的颜色编码,其中颜色的顺序是 BGR 而不是 RGB。【参考方案6】:
纯 Python(2 和 3),没有第三方依赖的 sn-p。
此函数写入压缩的真彩色(每像素 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)
Original source 另见:Rust Port from this question. 感谢@Evgeni Sergeev 的使用示例:https://***.com/a/21034111/432509
【讨论】:
这似乎正是我正在寻找的,但你能添加一些 cmets 吗?我看不出这是如何写入文件的。您是否必须将输出写入先前打开的文件中?谢谢! @PhilMacKay,只需将数据写入二进制文件即可。添加评论。 有人可以指定图像 (buf
) 应该采用的格式吗?它似乎不是一个 numpy 数组...
@christianmbrodbeck,一个字节数组(RGBARGBA...)
谢谢@ideasman42。我移植了这段代码for use in Blender。【参考方案7】:
@ideasman42 回答的附录:
def saveAsPNG(array, filename):
import struct
if any([len(row) != len(array[0]) for row in array]):
raise ValueError, "Array should have elements of equal size"
#First row becomes top row of image.
flat = []; map(flat.extend, reversed(array))
#Big-endian, unsigned 32-byte integer.
buf = b''.join([struct.pack('>I', ((0xffFFff & i32)<<8)|(i32>>24) )
for i32 in flat]) #Rotate from ARGB to RGBA.
data = write_png(buf, len(array[0]), len(array))
f = open(filename, 'wb')
f.write(data)
f.close()
所以你可以这样做:
saveAsPNG([[0xffFF0000, 0xffFFFF00],
[0xff00aa77, 0xff333333]], 'test_grid.png')
制作test_grid.png
:
(透明度也可以通过减少0xff
的高字节来实现。)
【讨论】:
【参考方案8】:matplotlib
:
import matplotlib
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.
【讨论】:
使用这个。但遭受内存泄漏 matplotlib.imsave() 在较新版本中 在 matplotlib 2+ 中是matplotlib.pyplot.imsave
@HughPerkins 尝试将Pillow 作为 Python 3 中的 PIL 替换
import matplotlib.pyplot as plt
然后plt.imsave('name.png', array)
【参考方案9】:
如果您碰巧已经使用 [Py]Qt,您可能会对qimage2ndarray 感兴趣。从 1.4 版(刚刚发布)开始,也支持 PySide,并且会有一个类似于 scipy 的微小的imsave(filename, array)
函数,但使用 Qt 而不是 PIL。对于 1.3,只需使用类似以下的内容:
qImage = array2qimage(image, normalize = False) # create QImage from ndarray
success = qImage.save(filename) # use Qt's image IO functions for saving PNG/JPG/..
(1.4的另一个优点是它是一个纯python解决方案,这使得它更加轻量级。)
【讨论】:
1.4 版本现已发布。 :-)(我相应地编辑了答案。)【参考方案10】:opencv
用于 python (documentation here)。
import cv2
import numpy as np
img = ... # Your image as a numpy array
cv2.imwrite("filename.png", img)
如果您需要进行除保存之外的更多处理,则很有用。
【讨论】:
为什么数组大小为 10?是什么导致在此解决方案中选择了 10 个? @Gathide 就像将一些任意 numpy 矩阵写入文件的示例。在现实生活中,用你的图片替换np.zeros((10,10))
。
当我使用 cv2 保存图像时,如何添加 cmap="gray"
之类的内容?
@Xocoatzin 链接断开?
@jtlz2 更新链接。【参考方案11】:
世界可能不需要另一个包来将 numpy 数组写入 PNG 文件,但对于那些无法获得足够的人,我最近在 github 上发布了 numpngw
:
https://github.com/WarrenWeckesser/numpngw
在 pypi 上:https://pypi.python.org/pypi/numpngw/
唯一的外部依赖是numpy。
这是存储库examples
目录中的第一个示例。基本线很简单
write_png('example1.png', img)
img
是一个 numpy 数组。该行之前的所有代码都是导入语句和创建img
的代码。
import numpy as np
from numpngw import write_png
# Example 1
#
# Create an 8-bit RGB image.
img = np.zeros((80, 128, 3), dtype=np.uint8)
grad = np.linspace(0, 255, img.shape[1])
img[:16, :, :] = 127
img[16:32, :, 0] = grad
img[32:48, :, 1] = grad[::-1]
img[48:64, :, 2] = grad
img[64:, :, :] = 127
write_png('example1.png', img)
这是它创建的 PNG 文件:
另外,我使用numpngw.write_apng
在Voronoi diagram in Manhattan metric 中创建动画。
【讨论】:
我很好奇,你的库和其他库有什么不同?它更快吗?它有花哨的功能吗? 几个特点:(1)它使用numpy数组。 (2) 仅使用 python 和 numpy 编写,因此不需要安装 C 库。 (3) 它可以创建动画PNG文件。 (4) 它提供了一个将matplotlib动画写成动画PNG文件的类。 谢谢!我很好奇它在性能方面与***.com/a/19174800/981933 相比如何,这也是纯python。前一种方法比 PIL 快 2 倍以上,非常棒。没关系,如果这不是你的目标:)【参考方案12】:假设你想要一张灰度图:
im = Image.new('L', (width, height))
im.putdata(an_array.flatten().tolist())
im.save("image.tiff")
【讨论】:
【参考方案13】:您可以在 Python 中使用“skimage”库
例子:
from skimage.io import imsave
imsave('Path_to_your_folder/File_name.jpg',your_array)
【讨论】:
【参考方案14】:如果您在python环境Spyder中工作,那么在变量资源管理器中右键单击数组,然后选择“显示图像”选项,再简单不过了。
这将要求您将图像保存到 dsik,主要是 PNG 格式。
在这种情况下不需要 PIL 库。
【讨论】:
【参考方案15】:scipy.misc
给出关于imsave
函数的弃用警告,并建议改用imageio
。
import imageio
imageio.imwrite('image_name.png', img)
【讨论】:
【参考方案16】:使用cv2.imwrite
。
import cv2
assert mat.shape[2] == 1 or mat.shape[2] == 3, 'the third dim should be channel'
cv2.imwrite(path, mat) # note the form of data should be height - width - channel
【讨论】:
【参考方案17】:对于那些正在寻找直接完整工作示例的人:
from PIL import Image
import numpy
w,h = 200,100
img = numpy.zeros((h,w,3),dtype=numpy.uint8) # has to be unsigned bytes
img[:] = (0,0,255) # fill blue
x,y = 40,20
img[y:y+30, x:x+50] = (255,0,0) # 50x30 red box
Image.fromarray(img).convert("RGB").save("art.png") # don't need to convert
另外,如果您想要高质量的 jpeg.save(file, subsampling=0, quality=100)
【讨论】:
【参考方案18】:Imageio 是一个 Python 库,它提供了一个简单的界面来读取和写入各种图像数据,包括动画图像、视频、体积数据和科学格式。它是跨平台的,可在 Python 2.7 和 3.4+ 上运行,并且易于安装。
这是灰度图像的示例:
import numpy as np
import imageio
# data is numpy array with grayscale value for each pixel.
data = np.array([70,80,82,72,58,58,60,63,54,58,60,48,89,115,121,119])
# 16 pixels can be converted into square of 4x4 or 2x8 or 8x2
data = data.reshape((4, 4)).astype('uint8')
# save image
imageio.imwrite('pic.jpg', data)
【讨论】:
【参考方案19】:为了将 numpy 数组保存为图像,U 有多种选择:
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) ...
【讨论】:
from PIL import Image
在加载模块所需的时间方面显然是赢家。【参考方案20】:
使用 pygame
所以这应该像我测试的那样工作(如果你没有 pygame,你必须安装 pygame,使用 pip -> pip install pygame 安装它(有时不起作用,所以在这种情况下你必须下载***或某事,但你可以在谷歌上查找)):
import pygame
pygame.init()
win = pygame.display.set_mode((128, 128))
pygame.surfarray.blit_array(win, yourarray)
pygame.display.update()
pygame.image.save(win, 'yourfilename.png')
记得根据你的数组改变显示的宽度和高度
这是一个例子,运行这段代码:
import pygame
from numpy import zeros
pygame.init()
win = pygame.display.set_mode((128, 128))
striped = zeros((128, 128, 3))
striped[:] = (255, 0, 0)
striped[:, ::3] = (0, 255, 255)
pygame.surfarray.blit_array(win, striped)
pygame.display.update()
pygame.image.save(win, 'yourfilename.png')
【讨论】:
以上是关于将 Numpy 数组保存为图像的主要内容,如果未能解决你的问题,请参考以下文章
将 tf.Tensor 转换为 numpy 数组,然后将其保存为图像而不使用 eager_execution
如何在保持分辨率的同时将2D float numpy数组无损保存到灰度图像中?