Speichern eines Numpy-Arrays als Bild

260

Ich habe eine Matrix vom Typ eines Numpy-Arrays. Wie würde ich es als Image auf die Festplatte schreiben? Jedes Format funktioniert (PNG, JPEG, BMP ...). Eine wichtige Einschränkung ist, dass PIL nicht vorhanden ist.

M456
quelle
12
Ich möchte nur darauf hinweisen, dass einige der Antworten unten und sicherlich einige der Leute, die kommen und diese Frage finden, nicht die oben aufgeführte Einschränkung erfüllen, ohne PIL zu sein . Da einige Fragesteller und einige Antworten diese Einschränkung vermeiden, ermutige ich jeden, der hier ist und nichts dagegen hat, dass PIL unten angezeigt wird, und alle Nicht-PIL-Antworten (neu oder alt) zu erwähnen, dass sie als PIL verwendet werden Art der Antwort, um sich von Antworten zu unterscheiden, die die ursprüngliche Einschränkung erfüllen.
Lindes

Antworten:

54

Sie können PyPNG verwenden . Es ist ein reiner Python (keine Abhängigkeiten) Open Source PNG Encoder / Decoder und unterstützt das Schreiben von NumPy Arrays als Images.

dF.
quelle
4
Denken Sie daran, die Werte für PNG auf den richtigen Bereich zu skalieren, normalerweise 0..255. Die Wertebereiche in neuronalen Netzen sind häufig 0..1 oder -1..1.
Tomáš Gavenčiak
8
PyPNG ist reines Python, das seine externen Abhängigkeiten reduziert, es jedoch viel langsamer macht als PIL und seine abgeleiteten Klassen. Das Speichern eines 3000x4000-Bildes auf meinem Computer dauerte beispielsweise mit PyPNG 4,05 Sekunden, mit scipy.misc.imsave jedoch nur 0,59 Sekunden (6x schneller).
Zvika
@ TomášGavenčiak - scipy.misc.imsave ist in den neueren Versionen von Scipy jetzt veraltet. Eine Alternative für einige Kommentare ist die Verwendung von imageio.imwrite ('image_file.jpg', Array)
Psi-Ed
258

Dies verwendet PIL, aber vielleicht finden es einige nützlich:

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

BEARBEITEN : Die aktuelle scipyVersion hat begonnen, alle Bilder so zu normalisieren, dass min (Daten) schwarz und max (Daten) weiß werden. Dies ist unerwünscht, wenn die Daten exakte Graustufen oder exakte RGB-Kanäle sein sollen. Die Lösung:

import scipy.misc
scipy.misc.toimage(image_array, cmin=0.0, cmax=...).save('outfile.jpg')
Steve Tjoa
quelle
19
imsave lebt in ... / scipy / misc / pilutil.py, die PIL
denis
5
Seien Sie vorsichtig beim Konvertieren in JPG, da es verlustbehaftet ist und Sie möglicherweise nicht in der Lage sind, die genauen Daten wiederherzustellen, die zum Generieren des Bildes verwendet wurden.
Feanil
8
Dies ist jetzt veraltet in scipy 0.19 use - scipy.io.imwrite
g.stevo
6
"imsave ist in SciPy 1.0.0 veraltet und wird in 1.2.0 entfernt" ( Scipy 1.1.0 doc )
noobar
15
scipy.misc.imsave ist veraltet. benutze import imageio; imageio.imwrite ('file_name.jpg', nmupy_array)
ChaosPredictor
228

Eine Antwort mit PIL (nur für den Fall, dass es nützlich ist).

gegeben ein numpy Array "A":

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

Sie können "jpeg" durch fast jedes gewünschte Format ersetzen. Weitere Details zu den Formaten hier

Migas
quelle
5
Image ist ein Modul von PIL. Machen Sie "Bild drucken .__ Datei__"
Juh_
10
Sehr hilfreich für diejenigen von uns, die hierher gewandert sind und PIL haben - ich denke, ich werde es verwenden from PIL import Image, um es klar zu halten ...
Salbei
4
Wenn Sie ein RGB-Bild haben, können Sie das Bild mit im = Image.fromarray (A) .convert ('RGB') abrufen.
Roger Veciana
Die Verwendung der dritten Achse eines Arrays von uint8 zum Codieren von RGB funktioniert mit dieser Methode. Das Modul PIL kann mit dem "Pip Install Pillow" installiert werden.
Bli
1
@Ludovico Verniani Es verzerrt keine Bilder, verwendet jedoch eine etwas ungewöhnliche Farbcodierung, bei der die Reihenfolge der Farben eher BGR als RGB ist.
Zvika
86

Mit matplotlib:

import matplotlib

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

Funktioniert mit matplotlib 1.3.1, ich weiß nichts über niedrigere Version. Aus der Dokumentationszeichenfolge:

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.

Geben Sie hier die Bildbeschreibung ein

christianbrodbeck
quelle
Verwenden Sie dies. Aber unter Speicherverlust leiden
SolessChong
matplotlib.imsave () in neueren Versionen
Vinay Lodha
6
Es ist matplotlib.pyplot.imsavein Matplotlib 2+
Aleksei Petrenko
1
@ HughPerkins versuchen Kissen als PIL-Ersatz in Python 3
Christianbrodbeck
10
import matplotlib.pyplot as pltund dannplt.imsave('name.png', array)
Alessandro Jacopson
61

Pure Python (2 & 3), ein Snippet ohne Abhängigkeiten von Drittanbietern.

Diese Funktion schreibt komprimierte Echtfarben-PNGs (4 Bytes pro Pixel) RGBA.

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

... Die Daten sollten direkt in eine als Binärdatei geöffnete Datei geschrieben werden, wie in:

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

ideasman42
quelle
2
Dies scheint genau das zu sein, wonach ich suche, aber können Sie einige Kommentare hinzufügen? Ich sehe nicht, wie dies in eine Datei schreibt. Müssen Sie die Ausgabe in eine zuvor geöffnete Datei schreiben? Vielen Dank!
PhilMacKay
1
@PhilMacKay, die Daten müssen nur in eine Binärdatei geschrieben werden. Kommentar hinzugefügt.
ideasman42
1
Kann jemand angeben, in welchem ​​Format das Bild ( buf) sein soll? Es scheint kein numpy Array zu sein ...
Christianbrodbeck
1
@christianmbrodbeck, ein bytearray (RGBARGBA ...)
ideasman42
1
Danke @ ideasman42. Ich habe diesen Code für die Verwendung in Blender portiert .
Emackey
57

Es gibt opencvfür Python ( Dokumentation hier ).

import cv2
import numpy as np

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

nützlich, wenn Sie mehr als nur speichern müssen.

Xocoatzin
quelle
1
Warum Array der Größe 10? Was führte zur Auswahl von 10 für diese Lösung?
Gathide
3
@Gathide Nur als Beispiel für das Schreiben einer beliebigen Numpy-Matrix in eine Datei. Im wirklichen Leben durch np.zeros((10,10))dein Bild ersetzen .
Xocoatzin
5
Wie kann ich etwas hinzufügen, cmap="gray"wenn ich das Bild mit cv2 speichere?
Mona Jalal
@Xocoatzin Link gebrochen?
jtlz2
1
@ jtlz2 Link aktualisiert.
Xocoatzin
30

Wenn Sie Matplotlib haben, können Sie Folgendes tun:

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

Dadurch wird der Plot gespeichert (nicht die Bilder selbst). Geben Sie hier die Bildbeschreibung ein

DopplerShift
quelle
10
Nein, für die Pyplot-Schnittstelle ist plt.figure () überflüssig. Außerdem benötigen Sie die Datei plt.show () nur, wenn Sie auch ein Figurenfenster sehen möchten. In diesem Fall wurde nur das Speichern einer Bilddatei gewünscht, sodass show () nicht aufgerufen werden musste.
DopplerShift
7
Beachten Sie, dass die resultierende Bilddatei die Achsen und den grauen Bereich der matlplotlib-Figur enthält - nicht nur die Pixeldaten.
Dave
1
funktioniert nicht, wenn Sie Ihr Skript auf einem Remote-Host ausführen und ohne Unterstützung der grafischen Oberfläche darauf zugreifen.
Temak
Wenn Sie das Bild in einem Notizbuch anzeigen möchten, können Sie Folgendes hinzufügen: >> "aus IPython.display Bild importieren" und dann >> "Bild (Dateiname = Dateiname)"
Robert
So entfernen Sie die Achse:plt.axis('off')
Yakout
15

Sie können die 'Skimage'-Bibliothek in Python verwenden

Beispiel:

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

scipy.miscgibt eine Warnung vor Verfall bezüglich der imsaveFunktion aus und schlägt imageiostattdessen die Verwendung von vor.

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

Nachtrag zur Antwort von @ 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()

So können Sie tun:

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

Produzieren test_grid.png:

Gitter aus Rot, Gelb, Dunkelaqua, Grau

(Transparenz funktioniert auch, indem das High-Byte von reduziert wird 0xff.)

Evgeni Sergeev
quelle
8

Für diejenigen, die ein direktes, voll funktionsfähiges Beispiel suchen:

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

auch, wenn Sie hochwertige JPEGs wollen
.save(file, subsampling=0, quality=100)

Pfütze
quelle
6

matplotlib svn hat eine neue Funktion zum Speichern von Bildern als Bild - keine Achsen usw. Es ist auch eine sehr einfache Funktion zum Backportieren, wenn Sie svn nicht installieren möchten (direkt aus image.py in matplotlib svn kopiert, entfernt die Docstring der Kürze halber):

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)
Autoplektisch
quelle
3

Die Welt braucht wahrscheinlich kein weiteres Paket, um ein Numpy-Array in eine PNG-Datei zu schreiben, aber für diejenigen, die nicht genug bekommen können, habe ich kürzlich numpngwGithub gestartet:

https://github.com/WarrenWeckesser/numpngw

und auf pypi: https://pypi.python.org/pypi/numpngw/

Die einzige externe Abhängigkeit ist numpy.

Hier ist das erste Beispiel aus dem examplesVerzeichnis des Repositorys. Die wesentliche Linie ist einfach

write_png('example1.png', img)

wo imgist ein numpy Array. Der gesamte Code vor dieser Zeile besteht aus Importanweisungen und zu erstellendem Code 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)

Hier ist die PNG-Datei, die erstellt wird:

example1.png

Warren Weckesser
quelle
Ich bin neugierig, wie unterscheidet sich Ihre Bibliothek von den anderen? Ist es schneller Hat es ausgefallene Funktionen?
F Lekschas
Einige Funktionen: (1) Es werden Numpy-Arrays verwendet. (2) Es wird nur mit Python und Numpy geschrieben, sodass keine C-Bibliothek installiert werden muss. (3) Es können animierte PNG-Dateien erstellt werden. (4) Es bietet eine Klasse zum Schreiben von Matplotlib-Animationen als animierte PNG-Dateien.
Warren Weckesser
Vielen Dank! Ich wäre gespannt, wie es im Vergleich zu stackoverflow.com/a/19174800/981933 in Bezug auf die Leistung ist, die auch reine Python ist. Die erstere Methode ist über 2x schneller als PIL, was ziemlich fantastisch ist. Vergiss es, wenn das nicht dein Ziel ist :)
F Lekschas
2

Angenommen, Sie möchten ein Graustufenbild:

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

Imageio ist eine Python-Bibliothek, die eine einfache Oberfläche zum Lesen und Schreiben einer Vielzahl von Bilddaten bietet, einschließlich animierter Bilder, Videos, Volumendaten und wissenschaftlicher Formate. Es ist plattformübergreifend, läuft unter Python 2.7 und 3.4+ und ist einfach zu installieren.

Dies ist ein Beispiel für ein Graustufenbild:

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
quelle
1

Wenn Sie [Py] Qt bereits verwenden, könnte Sie qimage2ndarray interessieren . Ab Version 1.4 (gerade veröffentlicht) wird auch PySide unterstützt, und es wird eine winzige imsave(filename, array)Funktion geben, die der von scipy ähnelt, jedoch Qt anstelle von PIL verwendet. Verwenden Sie mit 1.3 einfach Folgendes:

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

(Ein weiterer Vorteil von 1.4 ist, dass es sich um eine reine Python-Lösung handelt, die diese Lösung noch leichter macht.)

hans_meine
quelle
Die Version 1.4 ist ab sofort erhältlich. :-) (Ich habe die Antwort entsprechend bearbeitet.)
hans_meine
1

Wenn Sie in der Python-Umgebung Spyder arbeiten, kann es nicht einfacher sein, als einfach mit der rechten Maustaste auf das Array im Variablen-Explorer zu klicken und dann die Option Bild anzeigen zu wählen.

Geben Sie hier die Bildbeschreibung ein

Dadurch werden Sie aufgefordert, das Bild in dsik zu speichern, hauptsächlich im PNG-Format.

In diesem Fall wird keine PIL-Bibliothek benötigt.

abunickabhi
quelle
1

Verwenden Sie 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
quelle
0

Zum Speichern eines Numpy-Arrays als Bild haben Sie mehrere Möglichkeiten:

1) Best of Other: 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
quelle