Salvando uma matriz Numpy como uma imagem

261

Eu tenho uma matriz no tipo de uma matriz Numpy. Como eu o gravaria no disco como uma imagem? Qualquer formato funciona (png, jpeg, bmp ...). Uma restrição importante é que o PIL não está presente.

M456
fonte
12
Eu só gostaria de nota que algumas das respostas abaixo e, certamente, algumas das pessoas que chegam e encontrar esta pergunta, não atendem a restrição listados acima de ser sem PIL . Como alguns solicitantes e algumas respostas evitam essa restrição, incentivo qualquer pessoa que esteja aqui e não se importe com o PIL a olhar abaixo, e quaisquer respostas que não sejam do PIL (novas ou antigas) para mencionar que são usadas pelo PIL tipo de resposta, para se diferenciar das respostas que atendem à restrição original.
Lindes

Respostas:

54

Você pode usar o PyPNG . É um codificador / decodificador PNG de código aberto Python puro (sem dependências) e suporta gravação de matrizes NumPy como imagens.

dF.
fonte
4
Lembre-se de dimensionar os valores no intervalo correto para PNG, geralmente de 0 a 255. Os intervalos de valores nas redes neurais são frequentemente 0..1 ou -1..1.
Tomáš Gavenčiak 31/03
8
PyPNG é um Python puro, que reduz suas dependências externas, mas o torna muito mais lento que o PIL e suas classes derivadas. Por exemplo, salvar uma imagem de 3000 x 4000 na minha máquina levou 4,05 segundos com PyPNG, mas apenas 0,59 segundos com scipy.misc.imsave (6x mais rápido).
Zvika
@ TomášGavenčiak - scipy.misc.imsave agora está obsoleto nas versões mais recentes do Scipy. Uma alternativa alguns comentários abaixo é usar imageio.imwrite ('image_file.jpg', array)
Psi-Ed
259

Isso usa PIL, mas talvez alguns possam achar útil:

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

EDIT : A scipyversão atual começou a normalizar todas as imagens para que min (dados) fiquem pretos e max (dados) fiquem brancos. Isso é indesejável se os dados tiverem níveis exatos de cinza ou canais RGB exatos. A solução:

import scipy.misc
scipy.misc.toimage(image_array, cmin=0.0, cmax=...).save('outfile.jpg')
Steve Tjoa
fonte
19
vidas imsave em ... / scipy / misc / pilutil.py que usa PIL
denis
5
Tenha cuidado ao converter para jpg, pois está com perdas e, portanto, talvez não seja possível recuperar os dados exatos usados ​​para gerar a imagem.
Feanil
8
Isto agora é obsoleta no scipy 0,19 uso - scipy.io.imwrite
g.stevo
6
"imsave foi descontinuado no SciPy 1.0.0 e será removido no 1.2.0" ( Scipy 1.1.0 doc )
noobar
15
scipy.misc.imsave foi descontinuado. use import imageio; imageio.imwrite ('file_name.jpg', nmupy_array)
ChaosPredictor
228

Uma resposta usando PIL (apenas no caso de ser útil).

dada uma matriz numpy "A":

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

você pode substituir "jpeg" por quase qualquer formato que desejar. Mais detalhes sobre os formatos aqui

migas
fonte
5
A imagem é um módulo do PIL. Fazer "Impressão de imagens .__ file__"
Juh_
10
Muito útil para aqueles de nós que andamos aqui e temos PIL - acho que vou usar from PIL import Imagepara mantê-lo claro ...
sábio
4
Se você tiver uma imagem RGB, poderá obtê-la usando im = Image.fromarray (A) .convert ('RGB') Mais informações: stackoverflow.com/questions/4711880/…
Roger Veciana
O uso do terceiro eixo de uma matriz de uint8 para codificar RGB funciona com esse método. O módulo PIL pode ser instalado usando "travesseiro de instalação de pip".
bli
1
@Ludovico Verniani Ele não distorce as imagens, mas usa uma codificação de cores um tanto incomum na qual a ordem das cores é BGR e não RGB.
Zvika 11/06
88

Com matplotlib:

import matplotlib

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

Funciona com o matplotlib 1.3.1, não sei sobre a versão inferior. Da documentação:

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.

insira a descrição da imagem aqui

christianbrodbeck
fonte
Usando isso. Mas sofrendo de perda de memória
SolessChong
matplotlib.imsave () nas versões mais recentes
Vinay Lodha
6
É matplotlib.pyplot.imsaveem matplotlib 2+ #
Aleksei Petrenko 17/02
1
@HughPerkins tentar Pillow como substituto PIL em Python 3
christianbrodbeck
10
import matplotlib.pyplot as plte entãoplt.imsave('name.png', array)
Alessandro Jacopson
62

Pure Python (2 e 3), um snippet sem dependências de terceiros.

Essa função grava RGBAPNG compactado e em cores verdadeiras (4 bytes por pixel) .

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

... Os dados devem ser gravados diretamente em um arquivo aberto como binário, como em:

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

ideasman42
fonte
2
Parece ser exatamente o que estou procurando, mas você poderia adicionar alguns comentários? Não vejo como isso é gravado em um arquivo. Você precisa gravar a saída em um arquivo aberto anteriormente? Obrigado!
PhilMacKay
1
@PhilMacKay, os dados precisam ser gravados em um arquivo binário. comentário adicionado.
ideasman42
1
Alguém pode especificar em que formato a imagem ( buf) deve estar? Não parece ser uma matriz numpy ...
christianbrodbeck
1
@christianmbrodbeck, a bytearray (RGBARGBA ...)
ideasman42
1
Obrigado @ ideasman42. Portamos este código para uso no Blender .
emackey
57

Existe opencvpara python ( documentação aqui ).

import cv2
import numpy as np

cv2.imwrite("filename.png", np.zeros((10,10)))

útil se você precisar fazer mais processamento além de salvar.

Xocoatzin
fonte
1
Por que matriz de tamanho 10? O que levou à escolha dos 10 usados ​​nesta solução?
Gathide
3
@Athide Apenas como um exemplo de como escrever uma matriz numpy arbitrária em um arquivo. Na vida real, substitua np.zeros((10,10))pela sua imagem.
Xocoatzin 10/05
5
Como posso adicionar algo parecido cmap="gray"quando salvo a imagem usando o cv2?
Mona Jalal
@Xocoatzin Link quebrado?
Jtlz2
1
@ jtlz2 Link atualizado.
Xocoatzin
30

Se você possui o matplotlib, pode fazer:

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

Isso salvará o gráfico (não as imagens em si). insira a descrição da imagem aqui

DopplerShift
fonte
10
Não, para a interface pyplot, o plt.figure () é supérfluo. Além disso, você só precisa do plt.show () se quiser ver uma janela de figura - nesse caso, apenas o armazenamento de um arquivo de imagem era desejado, portanto não havia necessidade de chamar show ().
precisa saber é o seguinte
7
Observe que o arquivo de imagem resultante conterá os eixos e a área cinza da figura matlplotlib - não apenas os dados de pixel.
Dave
1
não funcionará se você executar o script no host remoto, fazendo o ssh sem suporte de interface gráfica.
Temak
Se você deseja mostrar a imagem em um bloco de anotações, pode adicionar o seguinte: >> "from IPython.display import Image" e >> "Image (filename = filename)"
Robert
Para remover o eixo:plt.axis('off')
yakout 22/12/18
15

Você pode usar a biblioteca 'skimage' em Python

Exemplo:

from skimage.io import imsave
imsave('Path_to_your_folder/File_name.jpg',your_array)
PURNENDU MISHRA
fonte
15

scipy.miscemite aviso de descontinuação sobre a imsavefunção e sugere o uso de imageio.

import imageio
imageio.imwrite('image_name.png', img)
Sefa
fonte
12

Adendo à resposta de @ 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()

Então você pode fazer:

saveAsPNG([[0xffFF0000, 0xffFFFF00],
           [0xff00aa77, 0xff333333]], 'test_grid.png')

Produção test_grid.png:

Grade de vermelho, amarelo, aqua-escuro, cinza

(A transparência também funciona, reduzindo o byte alto de 0xff.)

Evgeni Sergeev
fonte
8

Para quem procura um exemplo direto de trabalho completo:

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

Além disso, se você deseja jpeg de alta qualidade,
.save(file, subsampling=0, quality=100)

Poça
fonte
6

O matplotlib svn possui uma nova função para salvar imagens como apenas uma imagem - sem eixos, etc. também é uma função muito simples de backport, se você não deseja instalar o svn (copiado diretamente do image.py no matplotlib svn, removeu o por questões de concisão):

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)
Autoplectic
fonte
3

O mundo provavelmente não precisa de mais um pacote para escrever uma matriz numpy em um arquivo PNG, mas para aqueles que não conseguem o suficiente, recentemente coloquei numpngwno github:

https://github.com/WarrenWeckesser/numpngw

e no pypi: https://pypi.python.org/pypi/numpngw/

A única dependência externa é entorpecida.

Aqui está o primeiro exemplo do examplesdiretório do repositório. A linha essencial é simplesmente

write_png('example1.png', img)

onde imgé uma matriz numpy. Todo o código antes dessa linha é instruções de importação e código a ser criado 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)

Aqui está o arquivo PNG que ele cria:

example1.png

Warren Weckesser
fonte
Estou curioso, como a sua biblioteca é diferente das outras? É mais rápido? Tem características sofisticadas?
F Lekschas
Alguns recursos: (1) Utiliza matrizes numpy. (2) Ele é escrito usando apenas python e numpy, portanto não requer a instalação de uma biblioteca C. (3) Pode criar arquivos PNG animados. (4) Ele fornece uma classe para escrever animações matplotlib como arquivos PNG animados.
Warren Weckesser 31/03/19
Obrigado! Gostaria de saber como ele se compara ao stackoverflow.com/a/19174800/981933 em termos de desempenho, que também é puro python. O método anterior está acima de 2x mais rápido que o PIL, o que é bastante impressionante. Nevermind se isso não é o seu objetivo :)
F Lekschas
2

Supondo que você queira uma imagem em escala de cinza:

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

O Imageio é uma biblioteca Python que fornece uma interface fácil para ler e gravar uma ampla variedade de dados de imagem, incluindo imagens animadas, vídeo, dados volumétricos e formatos científicos. É multiplataforma, roda em Python 2.7 e 3.4+ e é fácil de instalar.

Este é um exemplo para a imagem em escala de cinza:

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)
Denis Rasulev
fonte
1

Se você já usa o [Py] Qt, pode estar interessado em qimage2ndarray . A partir da versão 1.4 (recém-lançada), o PySide também é suportado, e haverá uma pequena imsave(filename, array)função semelhante à do scipy's, mas usando Qt em vez de PIL. Com o 1.3, basta usar algo como o seguinte:

qImage = array2qimage(image, normalize = False) # create QImage from ndarray
success = qImage.save(filename) # use Qt's image IO functions for saving PNG/JPG/..

(Outra vantagem do 1.4 é que é uma solução python pura, o que torna isso ainda mais leve.)

hans_meine
fonte
A versão 1.4 já está disponível. :-) (I editada a resposta em conformidade.)
hans_meine
1

Se você estiver trabalhando no ambiente python Spyder, não será mais fácil do que clicar com o botão direito do mouse no array no explorador de variáveis ​​e escolher a opção Mostrar imagem.

insira a descrição da imagem aqui

Isso solicitará que você salve a imagem no dsik, principalmente no formato PNG.

Biblioteca PIL não será necessária neste caso.

abunickabhi
fonte
1

Use 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  
Christy Lee
fonte
1

para salvar uma matriz numpy como imagem, você tem várias opções:

1) o melhor de outros: 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) ...

nima farhadi
fonte