Zapisywanie tablicy Numpy jako obrazu

260

Mam macierz w rodzaju tablicy Numpy. Jak mam zapisać go na dysku jako obraz? Dowolny format działa (png, jpeg, bmp ...). Jednym ważnym ograniczeniem jest brak PIL.

M456
źródło
12
Chciałbym tylko zauważyć, że niektóre z poniższych odpowiedzi, a na pewno niektórzy ludzie, którzy przychodzą i szukają tego pytania, nie spełniają powyższego ograniczenia bycia bez PIL . Ponieważ niektórzy pytający i niektóre odpowiedzi unikają tego ograniczenia, zachęcam każdego, kto tu jest i nie przeszkadza, że ​​PIL zajrzy poniżej, i wszelkie odpowiedzi inne niż PIL (nowe lub stare), aby wspomnieć, że są używane PIL rodzaj odpowiedzi, aby odróżnić się od odpowiedzi spełniających pierwotne ograniczenie.
Lindes

Odpowiedzi:

54

Możesz użyć PyPNG . Jest to czysty koder / dekoder PNG typu open source w języku Python (bez zależności) i obsługuje zapisywanie tablic NumPy jako obrazy.

dF.
źródło
4
Pamiętaj, aby przeskalować wartości do odpowiedniego zakresu dla PNG, zwykle 0..255. Zakresy wartości w sieciach neuronowych wynoszą często 0..1 lub -1..1.
Tomáš Gavenčiak
8
PyPNG jest czystym Pythonem, co zmniejsza jego zewnętrzne zależności, ale czyni go znacznie wolniejszym niż PIL i jego pochodne klasy. Na przykład zapisanie obrazu 3000x4000 na moim komputerze zajęło 4,05 sekundy z PyPNG, ale tylko 0,59 sekundy z scipy.misc.imsave (6x szybciej).
Zvika
@ TomášGavenčiak - scipy.misc.imsave jest już nieaktualny w nowszych wersjach Scipy. Alternatywą dla kilku komentarzy poniżej jest użycie imageio.imwrite ('image_file.jpg', tablica)
Psi-Ed
258

Używa PIL, ale może niektórzy mogą się przydać:

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

EDYCJA : Obecna scipywersja zaczęła normalizować wszystkie obrazy, dzięki czemu min (dane) stają się czarne, a maks. (Dane) stają się białe. Jest to niepożądane, jeśli dane powinny mieć dokładny poziom szarości lub dokładne kanały RGB. Rozwiązanie:

import scipy.misc
scipy.misc.toimage(image_array, cmin=0.0, cmax=...).save('outfile.jpg')
Steve Tjoa
źródło
19
imsave mieszka w ... / scipy / misc / pilutil.py który wykorzystuje PIL
Denis
5
Zachowaj ostrożność podczas konwersji do formatu jpg, ponieważ jest on stratny i dlatego możesz nie być w stanie odzyskać dokładnych danych użytych do wygenerowania obrazu.
Feanil,
8
To jest teraz przestarzałe w przypadku użycia scipy 0.19 - scipy.io.imwrite
g.stevo
6
„Imsave jest przestarzałe w SciPy 1.0.0 i zostanie usunięte w 1.2.0” ( dokument Scipy 1.1.0 )
noobar
15
scipy.misc.imsave jest przestarzały. użyj importu imageio; imageio.imwrite ('nazwa_pliku.jpg', nmupy_array)
ChaosPredictor
228

Odpowiedź za pomocą PIL (na wypadek, gdyby była przydatna).

biorąc pod uwagę tablicę numpy „A”:

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

możesz zamienić „jpeg” na prawie dowolny format. Więcej informacji o formatach tutaj

migas
źródło
5
Obraz jest modułem PIL. Czy „wydrukuj plik .__ pliku__”
Juh_
10
Bardzo pomocne dla tych z nas, którzy tu wędrowali i mają PIL - myślę, że postaram się from PIL import Imageto wyjaśnić ...
mędrzec 18'13
4
Jeśli masz obraz RGB, możesz go uzyskać za pomocą im = Image.fromarray (A) .convert ('RGB') Więcej informacji: stackoverflow.com/questions/4711880/…
Roger Veciana
Użycie trzeciej osi tablicy uint8 do kodowania RGB działa z tą metodą. Moduł PIL można zainstalować za pomocą „poduszki instalacyjnej pip”.
bli
1
@Ludovico Verniani Nie zniekształca obrazów, ale używa nieco nietypowego kodowania kolorów, w którym kolejność kolorów to BGR, a nie RGB.
Zvika,
87

Z matplotlib:

import matplotlib

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

Działa z matplotlib 1.3.1, nie wiem o niższej wersji. Z dokumentacji:

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.

wprowadź opis zdjęcia tutaj

christianbrodbeck
źródło
Za pomocą tego. Ale cierpi na wyciek pamięci
SolessChong,
matplotlib.imsave () w nowszych wersjach
Vinay Lodha
6
Jest matplotlib.pyplot.imsavew Matplotlib 2+
Aleksei Petrenko
1
@HughPerkins wypróbuj Pillow jako zamiennik PIL w Pythonie 3
christianbrodbeck
10
import matplotlib.pyplot as plta następnieplt.imsave('name.png', array)
Alessandro Jacopson,
61

Czysty Python (2 i 3), fragment bez zależności stron trzecich.

Ta funkcja zapisuje skompresowane RGBApliki PNG o rzeczywistych kolorach (4 bajty na piksel) .

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

... Dane powinny być zapisane bezpośrednio do pliku otwartego jako plik binarny, jak w:

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

ideasman42
źródło
2
To wydaje się być dokładnie tym, czego szukam, ale czy mógłbyś dodać jakieś komentarze? Nie widzę, jak to zapisuje do pliku. Czy musisz zapisać dane wyjściowe we wcześniej otwartym pliku? Dzięki!
PhilMacKay
1
@PhilMacKay, dane muszą zostać zapisane w pliku binarnym. dodany komentarz.
ideasman42
1
Czy ktoś może określić, w jakim formacie bufma być image ( )? Nie wydaje się być tablicą numeryczną ...
christianbrodbeck
1
@christianmbrodbeck, a bytearray (RGBARGBA ...)
ideasman42
1
Dzięki @ ideasman42. Przeniesiłem ten kod do użytku w Blenderze .
emackey
57

Jest opencvdla Pythona ( tutaj dokumentacja ).

import cv2
import numpy as np

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

przydatne, jeśli chcesz wykonać więcej przetwarzania niż zapisywanie.

Xocoatzin
źródło
1
Dlaczego tablica o rozmiarze 10? Co doprowadziło do wyboru 10 zastosowanych w tym rozwiązaniu?
Gathide,
3
@Gathide Tylko jako przykład zapisania jakiejkolwiek dowolnej macierzy liczbowej do pliku. W prawdziwym życiu zastąp np.zeros((10,10))je swoim wizerunkiem.
Xocoatzin,
5
Jak mogę dodać coś takiego, cmap="gray"kiedy zapisuję obraz za pomocą CV2?
Mona Jalal,
@Xocoatzin Uszkodzony link?
jtlz2,
1
@ jtlz2 Zaktualizowano link.
Xocoatzin,
30

Jeśli masz matplotlib, możesz:

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

Spowoduje to zapisanie fabuły (a nie samych obrazów). wprowadź opis zdjęcia tutaj

DopplerShift
źródło
10
Nie, w przypadku interfejsu pyplot plt.figure () jest zbędny. Ponadto potrzebujesz tylko plt.show (), jeśli chcesz zobaczyć okno figury - w tym przypadku pożądane było tylko zapisanie pliku obrazu, więc nie było potrzeby wywoływania show ().
DopplerShift
7
Zauważ, że wynikowy plik obrazu będzie zawierał osie i szary obszar figury matlplotlib - nie tylko dane pikseli.
Dave
1
nie będzie działać, jeśli uruchomisz skrypt na zdalnym hoście, ssh-to na nim bez obsługi interfejsu graficznego.
Temak,
Jeśli chcesz pokazać obraz w notatniku, możesz dodać: >> „z IPython.display import Image”, a następnie >> „Image (nazwa pliku = nazwa pliku)”
Robert
Aby usunąć oś:plt.axis('off')
yakout
15

Możesz używać biblioteki „skimage” w Pythonie

Przykład:

from skimage.io import imsave
imsave('Path_to_your_folder/File_name.jpg',your_array)
PURNENDU MISHRA
źródło
15

scipy.miscwyświetla przestarzałe ostrzeżenie o imsavefunkcji i sugeruje użycie imageiozamiast niego.

import imageio
imageio.imwrite('image_name.png', img)
Sefa
źródło
12

Dodatek do odpowiedzi @ 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()

Możesz więc zrobić:

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

Produkcja test_grid.png:

Siatka w kolorze czerwonym, żółtym, ciemno-aqua, szarym

(Przejrzystość działa również poprzez zmniejszenie wysokiego bajtu od 0xff.)

Jewgienij Siergiejew
źródło
8

Dla tych, którzy szukają bezpośredniego w pełni działającego przykładu:

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

także, jeśli chcesz wysokiej jakości JPEG
.save(file, subsampling=0, quality=100)

Kałuża
źródło
6

matplotlib svn ma nową funkcję zapisywania obrazów jako obrazów - bez osi itp. jest to również bardzo prosta funkcja do backportowania, jeśli nie chcesz instalować svn (skopiowane bezpośrednio z image.py w matplotlib svn, usunęliśmy dokumentacja zwięzłości):

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)
Autoplektyka
źródło
3

Świat prawdopodobnie nie potrzebuje jeszcze jednego pakietu do zapisania tablicy numpy do pliku PNG, ale dla tych, którzy nie mogą dostać dość, niedawno zdecydowałem się numpngwna github:

https://github.com/WarrenWeckesser/numpngw

i na pypi: https://pypi.python.org/pypi/numpngw/

Jedyną zależnością zewnętrzną jest numpy.

Oto pierwszy przykład z exampleskatalogu repozytorium. Zasadnicza linia jest po prostu

write_png('example1.png', img)

gdzie imgjest tablica numpy. Cały kod przed tym wierszem to instrukcje importu i kod do utworzenia 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)

Oto plik PNG, który tworzy:

przyklad1.png

Warren Weckesser
źródło
Jestem ciekawy, czym twoja lib różni się od innych? Czy to jest szybsze? Czy ma fantazyjne funkcje?
F Lekschas,
Kilka funkcji: (1) Wykorzystuje tablice numpy. (2) Jest napisany przy użyciu tylko Pythona i Numpy, więc nie wymaga instalacji biblioteki C. (3) Może tworzyć animowane pliki PNG. (4) Zapewnia klasę do pisania animacji matplotlib jako animowanych plików PNG.
Warren Weckesser
Dzięki! Byłbym ciekawy, jak wypada w porównaniu z stackoverflow.com/a/19174800/981933 pod względem wydajności, która jest również czystym pythonem. Pierwsza metoda jest ponad 2x szybsza niż PIL, co jest całkiem niesamowite. Nieważne, czy to nie jest twój cel :)
F Lekschas
2

Zakładając, że chcesz mieć obraz w skali szarości:

im = Image.new('L', (width, height))
im.putdata(an_array.flatten().tolist())
im.save("image.tiff")
Guillaume Lebreton
źródło
2

Imageio to biblioteka Python, która zapewnia łatwy interfejs do odczytu i zapisu szerokiej gamy danych obrazu, w tym obrazów animowanych, wideo, danych wolumetrycznych i formatów naukowych. Jest wieloplatformowy, działa w Pythonie 2.7 i 3.4+ i jest łatwy w instalacji.

Oto przykład obrazu w skali szarości:

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
źródło
1

Jeśli zdarzyło Ci się już używać [Py] Qt, możesz zainteresować się qimage2ndarray . Począwszy od wersji 1.4 (właśnie wydanej), PySide jest również obsługiwany, i będzie mała imsave(filename, array)funkcja podobna do scipy's, ale wykorzystująca Qt zamiast PIL. W wersji 1.3 po prostu użyj czegoś takiego:

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

(Kolejną zaletą 1.4 jest to, że jest to rozwiązanie czysto pythonowe, co czyni go jeszcze bardziej lekkim.)

hans_meine
źródło
Wersja 1.4 jest już dostępna. :-) (odpowiednio zredagowałem odpowiedź).
hans_meine,
1

Jeśli pracujesz w środowisku Spyder w języku Python, nie może to być łatwiejsze niż kliknięcie tablicy prawym przyciskiem myszy w eksploratorze zmiennych, a następnie wybranie opcji Pokaż obraz.

wprowadź opis zdjęcia tutaj

To poprosi o zapisanie obrazu do dsik, głównie w formacie PNG.

W tym przypadku biblioteka PIL nie będzie potrzebna.

abunickabhi
źródło
1

Zastosowanie 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
źródło
0

do zapisywania tablicy numpy jako obrazu, masz kilka możliwości:

1) najlepsze z innych: 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
źródło