Jak przekonwertować tablicę NumPy na obraz PIL przy użyciu mapy kolorów matplotlib

134

Mam prosty problem, ale nie mogę znaleźć dobrego rozwiązania.

Chcę wziąć tablicę NumPy 2D, która reprezentuje obraz w skali szarości i przekonwertować ją na obraz RGB PIL, stosując niektóre z map kolorów matplotlib.

Mogę uzyskać rozsądny wynik w formacie PNG za pomocą pyplot.figure.figimagepolecenia:

dpi = 100.0
w, h = myarray.shape[1]/dpi, myarray.shape[0]/dpi
fig = plt.figure(figsize=(w,h), dpi=dpi)
fig.figimage(sub, cmap=cm.gist_earth)
plt.savefig('out.png')

Chociaż mógłbym to dostosować, aby uzyskać to, czego chcę (prawdopodobnie używając StringIO do uzyskania obrazu PIL), zastanawiam się, czy nie ma prostszego sposobu na zrobienie tego, ponieważ wydaje się to bardzo naturalny problem wizualizacji obrazu. Powiedzmy coś takiego:

colored_PIL_image = magic_function(array, cmap)
heltonbiker
źródło

Odpowiedzi:

222

Dość zajęty jednolinijkowy, ale oto jest:

  1. Najpierw upewnij się, że tablica NumPy myarrayjest znormalizowana z maksymalną wartością w 1.0.
  2. Zastosuj mapę kolorów bezpośrednio do myarray.
  3. Przeskaluj do 0-255zakresu.
  4. Konwertuj na liczby całkowite, używając np.uint8().
  5. Użyj Image.fromarray().

I jesteś skończony:

from PIL import Image
from matplotlib import cm
im = Image.fromarray(np.uint8(cm.gist_earth(myarray)*255))

z plt.savefig():

Tutaj wprowadź opis obrazu

z im.save():

Tutaj wprowadź opis obrazu

fraxel
źródło
7
„Zastosuj mapę kolorów bezpośrednio do myarray” części wyciętej prosto do serca! Nie wiedziałem, że to możliwe, dziękuję!
heltonbiker
34
Studiując dokumentację dotyczącą LinearSegmentedColormap (z której cm.gist_earth jest instancją), odkryłem, że można ją wywołać z argumentem „bajty”, który już konwertuje ją na uint8. Następnie linijka staje się znacznie cichsza:im = Image.fromarray(cm.gist_earth(myarray, bytes=True))
heltonbiker
1
@CiprianTomoiaga, kształt tablicy powinien mieć żądane wymiary obrazu. Na przykład obraz VGA zostałby wygenerowany z tablicy z kształtem (1024,768). Należy zauważyć, że dotyczy to obrazów monochromatycznych. Jest to ważne, ponieważ zazwyczaj podczas konwersji obrazu RGB na tablicę jego kształt to na przykład (1024,768,3), ponieważ ma trzy kanały.
heltonbiker
5
Otrzymuję błądNameError: name 'cm' is not defined
rnso
10
@msofrom matplotlib import cm
Quantum7
10
  • input = numpy_image
  • np.unit8 -> konwertuje na liczby całkowite
  • convert ('RGB') -> konwertuje na RGB
  • Image.fromarray -> zwraca obiekt obrazu

    from PIL import Image
    import numpy as np
    
    PIL_image = Image.fromarray(np.uint8(numpy_image)).convert('RGB')
    
    PIL_image = Image.fromarray(numpy_image.astype('uint8'), 'RGB')
Aravinda_gn
źródło
5
Mam nadzieję, że to rozwiąże problem, ale proszę dodać wyjaśnienie swojego kodu, aby użytkownik uzyskał doskonałe zrozumienie, czego naprawdę chce.
Jaimil Patel
1
Dobra, zaktualizowana odpowiedź. Poprzednie są sprzed kilku lat.
Catalina Chircu
7

Metoda opisana w zaakceptowanej odpowiedzi nie działała u mnie nawet po zastosowaniu zmian wymienionych w jej komentarzach. Ale poniższy prosty kod zadziałał:

import matplotlib.pyplot as plt
plt.imsave(filename, np_array, cmap='Greys')

np_array może być tablicą 2D z wartościami z zakresu 0..1 floats o2 0..255 uint8 iw takim przypadku potrzebuje cmap. W przypadku tablic 3D cmap zostanie zignorowany.

Shital Shah
źródło