Как преобразовать массив NumPy в изображение PIL, применяя цветовую карту matplotlib

134

У меня простая проблема, но я не могу ее решить.

Я хочу взять 2D-массив NumPy, который представляет изображение в оттенках серого, и преобразовать его в изображение RGB PIL, применяя некоторые из цветовых карт matplotlib.

Я могу получить разумный вывод PNG с помощью pyplot.figure.figimageкоманды:

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

Хотя я мог бы адаптировать это, чтобы получить то, что я хочу (возможно, используя StringIO, получаю изображение PIL), мне интересно, нет ли более простого способа сделать это, поскольку это кажется очень естественной проблемой визуализации изображения. Скажем, примерно так:

colored_PIL_image = magic_function(array, cmap)
heltonbiker
источник

Ответы:

222

Довольно загруженный однострочник, но вот он:

  1. Сначала убедитесь, что ваш массив NumPy myarrayнормализован с максимальным значением в 1.0.
  2. Примените палитру непосредственно к myarray.
  3. Измените масштаб до 0-255диапазона.
  4. Преобразуйте в целые числа, используя np.uint8().
  5. Используйте Image.fromarray().

И вы сделали:

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

с plt.savefig():

Введите описание изображения здесь

с im.save():

Введите описание изображения здесь

Fraxel
источник
7
Часть «Нанесите цветовую карту прямо на myarray» прямо в самое сердце! Я не знал, что это возможно, спасибо!
heltonbiker
34
Изучая документацию о LinearSegmentedColormap (из которой cm.gist_earth является экземпляром), я обнаружил, что его можно вызвать с помощью аргумента «bytes», который уже преобразует его в uint8. Затем im = Image.fromarray(cm.gist_earth(myarray, bytes=True))
однострочный текст
1
@CiprianTomoiaga, форма массива должна соответствовать размерам изображения, которые вы хотите. Например, изображение VGA будет сгенерировано из массива с формой (1024 768). Вы должны заметить, что это применимо к монохромным изображениям. Это важно, потому что обычно, когда вы конвертируете изображение RGB в массив, его форма, например, (1024,768,3), так как у него три канала.
heltonbiker
5
Я получаю сообщение об ошибкеNameError: name 'cm' is not defined
rnso
10
@msofrom matplotlib import cm
Quantum7 02
10
  • input = numpy_image
  • np.unit8 -> преобразует в целые числа
  • convert ('RGB') -> конвертирует в RGB
  • Image.fromarray -> возвращает объект изображения

    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
источник
5
Надеюсь, это решит проблему, но, пожалуйста, добавьте к нему объяснение своего кода, чтобы пользователь получил полное представление о том, чего он действительно хочет.
Джаймил Патель,
1
Хороший обновленный ответ. Предыдущие - несколько лет назад.
Каталина Чирку,
7

Метод, описанный в принятом ответе, не работал у меня даже после внесения изменений, упомянутых в его комментариях. Но приведенный ниже простой код работал:

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

np_array может быть двухмерным массивом со значениями от 0 до 1 с плавающей запятой o2 от 0 до 255 uint8, и в этом случае ему нужен cmap. Для трехмерных массивов cmap игнорируется.

Шитал Шах
источник