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.


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.


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

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


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


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)


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.


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


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)

15

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

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

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


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)


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)

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


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

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)

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


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.


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  

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.