将 Numpy 数组保存为图像

2024-12-30 08:41:00
admin
原创
55
摘要:问题描述:我有一个 Numpy 数组类型的矩阵。我该如何将其作为图像写入磁盘?任何格式都可以(png、jpeg、bmp……)。一个重要的限制是不存在 PIL。解决方案 1:使用PIL,通过执行以下操作保存 NumPy 数组arr:from PIL import Image im = Image.fromarr...

问题描述:

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


解决方案 1:

使用PIL,通过执行以下操作保存 NumPy 数组arr

from PIL import Image
im = Image.fromarray(arr)
im.save("your_file.jpeg")

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

解决方案 2:

这使用了 PIL,但也许有些人会发现它很有用:

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

编辑:当前scipy版本开始对所有图像进行标准化,以便最小(数据)变为黑色,最大(数据)变为白色。如果数据应该是精确的灰度级或精确的 RGB 通道,则这是不必要的。解决方案:

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

解决方案 3:

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.

在此处输入图片描述

解决方案 4:

这是opencv适用于 python 的版本(文档在此处)。

import cv2
import numpy as np

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

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

如果您需要进行除了保存之外的更多处理,这很有用。

解决方案 5:

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

此函数写入压缩的真彩色(每像素 4 个字节)RGBAPNG。

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

解决方案 6:

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

解决方案 7:

要将 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) 太平船务

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

4)...

解决方案 8:

如果你有 matplotlib,你可以执行以下操作:

import matplotlib.pyplot as plt
plt.imshow(matrix) #Needs to be in row,col order
plt.savefig(filename)

这将保存情节(而不是图像本身)。
在此处输入图片描述

解决方案 9:

scipy.misc给出关于函数的弃用警告imsave并建议使用imageio

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

解决方案 10:

您可以使用 Python 中的“skimage”库

例子:

from skimage.io import imsave
imsave('Path_to_your_folder/File_name.jpg',your_array)

解决方案 11:

@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。)

解决方案 12:

对于那些寻找直接且完整工作示例的人来说:

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)

解决方案 13:

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)

解决方案 14:

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)

解决方案 15:

这个世界可能不需要另一个将 numpy 数组写入 PNG 文件的包,但是对于那些还不够的人来说,我最近numpngw在 github 上发布了一个:

https://github.com/WarrenWeckesser/numpngw

在 pypi 上: https: //pypi.python.org/pypi/numpngw/

唯一的外部依赖是 numpy。

这是存储库目录中的第一个示例examples。关键行很简单

write_png('example1.png', img)

其中img是 numpy 数组。该行之前的所有代码都是 import 语句和创建的代码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 文件:

示例1.png

另外,我还曾经在曼哈顿度量中的 Voronoi 图numpngw.write_apng中创建动画。

解决方案 16:

假设您想要一张灰度图像:

im = Image.new('L', (width, height))
im.putdata(an_array.flatten().tolist())
im.save("image.tiff")

解决方案 17:

以下答案中包含@Nima Farhadi 在时间测量方面提出的方法。

最快的是 CV2,但将颜色顺序从 RGB 更改为 BGR 很重要。最简单的是 matplotlib。

重要的是确保数组具有无符号整数格式 uint8/16/32。

代码:

#Matplotlib
from matplotlib import pyplot as plt
plt.imsave('c_plt.png', c.astype(np.uint8))

#PIL
from PIL import Image
image = Image.fromarray(c.astype(np.uint8))
image.save('c_pil.png')


#CV2, OpenCV
import cv2
cv2.imwrite('c_cv2.png', cv2.cvtColor(c, cv2.COLOR_RGB2BGR))

在此处输入图片描述

解决方案 18:

如果您碰巧已经使用过 [Py]Qt,那么您可能会对qimage2ndarray感兴趣。从版本 1.4(刚刚发布)开始,PySide 也受支持,并且将有一个imsave(filename, array)类似于 scipy 的小函数,但使用 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 解决方案,这使得它更加轻量级。)

解决方案 19:

使用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  

解决方案 20:

如果您在 python 环境 Spyder 中工作,那么最简单的方法是右键单击变量资源管理器中的数组,然后选择“显示图像”选项。

在此处输入图片描述

这将要求您将图像保存到 dsik,大多数为 PNG 格式。

在这种情况下不需要 PIL 库。

解决方案 21:

使用 pygame

所以这应该可以像我测试的那样工作(如果你没有 pygame,那么你必须安装 pygame,使用 pip -> pip install pygame 安装它(这有时不起作用,所以在这种情况下你必须下载 wheel 或其他东西,但你可以在谷歌上查找)):

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

解决方案 22:

我附加了一个将 npy 转换为图像的简单例程。

from PIL import Image
import matplotlib

img = np.load('flair1_slice75.npy')

matplotlib.image.imsave("G1_flair_75.jpeg", img)

解决方案 23:

您可以使用此代码通过 PIL python 库将您的 Npy 数据转换为图像,因为这个库主要处理图像,在这里,我使用 numpy 在数据集上下文中加载图像格式:

#importing the libraries
from PIL import Image
import numpy as np

data = np.load('/kaggle/input/objects-dataset/nmbu.npy')
im = Image.fromarray(data, 'RGB')
#saving the image from the npy format
im.save("your_file.jpeg")

解决方案 24:

基于@ideasman42的回答和Evgeni Sergeev的附录,这里是一个将numpy数组转换为图像的实现。

注意:此实现将a[1,1,:]图像放在左上角

为了揭开 png 格式的神秘面纱,我从http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html粘贴了一些信息

此实现显示:

  • 使用调色板并缩放值的 nxm 数组

  • nxmx3 RGB 数组,具有一种透明颜色;忽略调色板

  • nxmx4 RGBA 数组;忽略调色板和透明颜色

它返回一个可以传递给 PhotoImage 的字节字符串。它不像下面 Warren Weckesser 写的那样严格,但它以透明的方式将数据传入 tkinter。

# https://stackoverflow.com/questions/902761/saving-a-numpy-array-as-an-image
# http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html
# we insist on
#  o values between 0-1
#  o g, ga, rgb, rgba
#  o nxmx 1/2/3/3
import numpy as np
import zlib, struct

def topngbytes(a:np.ndarray,transparentcolor=[1,2,3],hicolor=[255,95,0]):
    sz = a.shape
    lensz=len(sz)
    height,width=sz[0:2]
    colortype=0
    palette=None

    # Color    Allowed    Interpretation
    #    Type    Bit Depths
    #
    #    0       1,2,4,8,16  Each pixel is a grayscale sample.
    #    2       8,16        Each pixel is an R,G,B triple.
    #    3       1,2,4,8     Each pixel is a palette index;
    #                        a PLTE chunk must appear.
    #    4       8,16        Each pixel is a grayscale sample,
    #                        followed by an alpha sample.
    #    6       8,16        Each pixel is an R,G,B triple,
    #                        followed by an alpha sample.
    if lensz==2:
        colortype=3        # 8bit palette
        amin=np.min(a)
        da=np.max(a)-amin
        if da==0: a=a*0+127
        elif da<72 or da>255: a=255/da*(a-amin)

        cmin = np.array(transparentcolor,dtype=float)  # generate a two tone palette
        dc = hicolor - cmin
        palette = np.zeros(shape=(256, 3), dtype=np.uint8)
        for i, r in enumerate(palette): r[:] = cmin + dc/255. * i
            
    elif lensz==3:
        n=sz[-1]                    #color info always the last dimension
        if n==2: colortype=4        # grey+alpha
        elif n==3: colortype=2      # rgb
        elif n==4: colortype=6      # rgba
        else: raise(ValueError(f"mImg: color dimension must be nxmx 1,2,3 or 4, not {sz}"))

    buf = b''.join( b'x00' + row.tobytes() for row in a.astype(dtype=np.uint8))


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

    # first chunc is    IHDR
    # Width:              4 bytes
    # Height:             4 bytes
    # Bit depth:          1 byte  --> we use 8  = 0-255
    # Color type:         1 byte
    # Compression method: 1 byte
    # Filter method:      1 byte
    # Interlace method:   1 byte

    # The PLTE chunk contains from 1 to 256 palette entries, each a three-byte series of the form:
    #
    # Red:   1 byte (0 = black, 255 = red)
    # Green: 1 byte (0 = black, 255 = green)
    # Blue:  1 byte (0 = black, 255 = blue)
    # The number of entries is determined from the chunk length. A chunk length not divisible by 3 is an error.
    #
    # This chunk must appear for color type 3, and can appear for color types 2 and 6;
    # it must not appear for color types 0 and 4. If this chunk does appear, it must precede the first IDAT chunk.
    # There must not be more than one PLTE chunk.
    #
    # For color type 3 (indexed color), the PLTE chunk is required.
    # The first entry in PLTE is referenced by pixel value 0

    IHDR=png_pack(b'IHDR', struct.pack("!2I5B", width, height, 8, colortype, 0, 0, 0))
    PLTE = b'' if (colortype in [0,4]) or palette is None else png_pack(b'PLTE',palette.tobytes())
    t=transparentcolor
    tRNS = png_pack(b'tRNS', struct.pack("!6B", t[0], 0, t[1], 0, t[2], 0))
    IDAT = png_pack(b'IDAT', zlib.compress(buf, 9))
    IEND = png_pack(b'IEND', b'')

    return b''.join([b'x89PNG
x1a
',IHDR,PLTE,tRNS,IDAT,IEND])
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   990  
  在项目管理领域,CDCP(Certified Data Center Professional)认证评审是一个至关重要的环节,它不仅验证了项目团队的专业能力,还直接关系到项目的成功与否。在这一评审过程中,沟通技巧的运用至关重要。有效的沟通不仅能够确保信息的准确传递,还能增强团队协作,提升评审效率。本文将深入探讨CDCP...
华为IPD流程   26  
  IPD(Integrated Product Development,集成产品开发)是一种以客户需求为核心、跨部门协同的产品开发模式,旨在通过高效的资源整合和流程优化,提升产品开发的成功率和市场竞争力。在IPD培训课程中,掌握关键成功因素是确保团队能够有效实施这一模式的核心。以下将从五个关键成功因素展开讨论,帮助企业和...
IPD项目流程图   27  
  华为IPD(Integrated Product Development,集成产品开发)流程是华为公司在其全球化进程中逐步构建和完善的一套高效产品开发管理体系。这一流程不仅帮助华为在技术创新和产品交付上实现了质的飞跃,还为其在全球市场中赢得了显著的竞争优势。IPD的核心在于通过跨部门协作、阶段性评审和市场需求驱动,确保...
华为IPD   26  
  华为作为全球领先的通信技术解决方案提供商,其成功的背后离不开一套成熟的管理体系——集成产品开发(IPD)。IPD不仅是一种产品开发流程,更是一种系统化的管理思想,它通过跨职能团队的协作、阶段评审机制和市场需求驱动的开发模式,帮助华为在全球市场中脱颖而出。从最初的国内市场到如今的全球化布局,华为的IPD体系在多个领域展现...
IPD管理流程   53  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用