Сохранение массива Numpy в виде изображения

261

У меня есть матрица в виде массива Numpy. Как бы я записал его на диск как образ? Работает любой формат (png, jpeg, bmp ...). Одним из важных ограничений является то, что PIL отсутствует.

M456
источник
12
Я просто хотел бы отметить, что некоторые из ответов ниже, и, конечно, некоторые из людей, которые приходят и находят этот вопрос, не соответствуют указанному выше ограничению - быть без PIL . Поскольку некоторые спрашивающие и некоторые ответы оба избегают этого ограничения, я призываю всех, кто здесь, и не возражает против того, чтобы PIL смотрел ниже, и любые не-PIL ответы (новые или старые), чтобы упомянуть, что они используются PIL. тип ответа, чтобы отличить себя от ответов, отвечающих первоначальному ограничению.
Линд
Кажется связанным: stackoverflow.com/questions/33480297/viewing-npy-images
xxx ---

Ответы:

54

Вы можете использовать PyPNG . Это чистый Python (без зависимостей) открытый кодировщик / декодер PNG с открытым исходным кодом, и он поддерживает запись массивов NumPy в виде изображений.

дР.
источник
4
Не забудьте масштабировать значения до нужного диапазона для PNG, обычно 0..255. Диапазоны значений в нейронных сетях часто равны 0..1 или -1..1.
Томаш Гавенчяк
8
PyPNG - это чистый Python, который уменьшает свои внешние зависимости, но делает его намного медленнее, чем PIL и его производные классы. Например, сохранение изображения 3000x4000 на моем компьютере заняло 4,05 секунды с PyPNG, но всего 0,59 секунды с scipy.misc.imsave (в 6 раз быстрее).
Звика
@ TomášGavenčiak - scipy.misc.imsave больше не поддерживается в новых версиях Scipy. Альтернативой нескольким комментариям ниже является использование imageio.imwrite ('image_file.jpg', array)
Пси-Эд
259

Это использует PIL, но, возможно, некоторые могут найти это полезным:

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

РЕДАКТИРОВАТЬ : текущая scipyверсия начала нормализовать все изображения так, чтобы min (данные) стали черными, а max (данные) стали белыми. Это нежелательно, если данные должны иметь точные уровни серого или точные каналы RGB. Решение:

import scipy.misc
scipy.misc.toimage(image_array, cmin=0.0, cmax=...).save('outfile.jpg')
Стив Тджоа
источник
19
imsave живет в ... / scipy / misc / pilutil.py, который использует PIL
Денис
5
Будьте осторожны при конвертации в jpg, так как это с потерями, и поэтому вы не сможете восстановить точные данные, использованные для генерации изображения.
Феанил
8
Это теперь устарело при использовании scipy 0.19 - scipy.io.imwrite
g.stevo
6
«imsave устарела в SciPy 1.0.0 и будет удалена в 1.2.0» ( Scipy 1.1.0 doc )
noobar
15
scipy.misc.imsave устарела. использовать импорт imageio; imageio.imwrite ('file_name.jpg', nmupy_array)
ChaosPredictor
228

Ответ с использованием PIL (на всякий случай, если это полезно).

учитывая массив N "n"

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

Вы можете заменить «JPEG» практически любой формат, который вы хотите. Подробнее о форматах здесь

Мигас
источник
5
Изображение представляет собой модуль PIL. Сделайте «печать изображения .__ файл__»
Juh_
10
Очень полезно для тех из нас, кто бродил здесь и у кого есть PIL - я думаю, я буду использовать, from PIL import Imageчтобы держать это в чистоте ...
мудрец
4
Если у вас есть RGB-изображение, вы можете получить его с помощью im = Image.fromarray (A) .convert ('RGB'). Дополнительная информация: stackoverflow.com/questions/4711880/…
Roger Veciana
Использование третьей оси массива uint8 для кодирования RGB работает с этим методом. Модуль PIL может быть установлен с помощью «pip install pillow».
ло
1
@Ludovico Verniani Это не искажает изображения, но оно использует несколько необычную цветовую кодировку, в которой порядок цветов - BGR, а не RGB.
Звика
88

С matplotlib:

import matplotlib

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

Работает с Matplotlib 1.3.1, я не знаю о более низкой версии. Из строки документации:

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.

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

christianbrodbeck
источник
Используя это. Но страдает от утечки памяти
SolessChong
matplotlib.imsave () в более новых версиях
Vinay Lodha
6
Это matplotlib.pyplot.imsaveв матплотлибе 2+
Алексей Петренко
1
@HughPerkins попробовать подушку в качестве замены PIL в Python 3
christianbrodbeck
10
import matplotlib.pyplot as pltа затемplt.imsave('name.png', array)
Алессандро Якопсон
62

Pure Python (2 и 3), фрагмент без сторонних зависимостей.

Эта функция записывает сжатые RGBAPNG- изображения истинного цвета (4 байта на пиксель) .

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

... Данные должны быть записаны непосредственно в файл, открытый в двоичном виде, как в:

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

ideasman42
источник
2
Кажется, это именно то, что я ищу, но не могли бы вы добавить несколько комментариев? Я не вижу, как это пишет в файл. Нужно ли записывать вывод в ранее открытый файл? Спасибо!
PhilMacKay
1
@PhilMacKay, данные просто должны быть записаны в двоичный файл. добавлен комментарий.
ideasman42
1
Кто-то может указать, в каком формате bufдолжно быть изображение ( )? Похоже, это не просто массив ...
christianbrodbeck
1
@christianmbrodbeck, bytearray (RGBARGBA ...)
ideasman42
1
Спасибо @ ideasman42. Я портировал этот код для использования в Blender .
Emackey
57

Есть opencvдля Python ( документация здесь ).

import cv2
import numpy as np

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

полезно, если вам нужно больше обрабатывать, чем сохранять.

Xocoatzin
источник
1
Почему массив размером 10? Что привело к выбору 10 используемых в этом решении?
Гатиде
3
@Gathide Так же, как пример записи произвольной матрицы в файл. В реальной жизни замените np.zeros((10,10))своим изображением.
Ксокоацин
5
Как я могу добавить что-то вроде, cmap="gray"когда я сохраняю изображение с помощью cv2?
Мона Джалал
@Xocoatzin Неработающая ссылка?
jtlz2
1
@ jtlz2 Обновленная ссылка.
Ксокоацин
30

Если у вас есть matplotlib, вы можете сделать:

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

Это сохранит сюжет (не сами изображения). введите описание изображения здесь

Допплеровский
источник
10
Нет, для интерфейса pyplot plt.figure () является излишним. Кроме того, вам нужен только plt.show (), если вы хотите увидеть также окно с рисунком - в этом случае требуется только сохранение файла изображения, поэтому нет необходимости вызывать show ().
DopplerShift
7
Обратите внимание, что полученный файл изображения будет содержать оси и серую область рисунка matlplotlib, а не только данные пикселей.
Дэйв
1
не будет работать, если вы запустите свой скрипт на удаленном хосте, подключившись к нему без поддержки графического интерфейса.
Темак
Если вы хотите показать изображение в блокноте, вы можете добавить следующее: >> «из IPython.display import Image», а затем >> «Image (filename = filename)»
Robert
Чтобы снять ось:plt.axis('off')
yakout
15

Вы можете использовать библиотеку 'Skimage' в Python

Пример:

from skimage.io import imsave
imsave('Path_to_your_folder/File_name.jpg',your_array)
ПУРНЕНДУ МИШРА
источник
15

scipy.miscвыдает предупреждение об устаревании imsaveфункции и предлагает использовать imageioвместо этого.

import imageio
imageio.imwrite('image_name.png', img)
Сефа
источник
12

Приложение к ответу @ 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()

Так что вы можете сделать:

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

Производство test_grid.png:

Сетка красная, желтая, темно-аква, серая

(Прозрачность также работает, уменьшая старший байт от 0xff.)

Евгений Сергеев
источник
8

Для тех, кто ищет прямой полностью рабочий пример:

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

Кроме того, если вы хотите высокое качество JPEG
.save(file, subsampling=0, quality=100)

лужа
источник
6

Matplotlib SVN имеет новую функцию для сохранения изображений в виде просто изображения - без осей и т. д. Это очень простая функция для бэкпорта тоже, если вы не хотите устанавливать SVN (скопировано прямо из image.py в Matplotlib SVN, удалил документация для краткости):

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)
Autoplectic
источник
3

Мир, вероятно, не нуждается в еще одном пакете для записи массива в PNG-файл, но для тех, кто не может получить достаточно, я недавно выложил numpngw github:

https://github.com/WarrenWeckesser/numpngw

и по пипи: https://pypi.python.org/pypi/numpngw/

Единственная внешняя зависимость - тупая.

Вот первый пример из examplesкаталога репозитория. Основная линия просто

write_png('example1.png', img)

где imgмассив NumPy. Весь код перед этой строкой - операторы импорта и код для создания 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)

Вот файл PNG, который он создает:

example1.png

Уоррен Векессер
источник
Мне любопытно, чем ваша библиотека отличается от других? Это быстрее? У этого есть причудливые особенности?
Ф Лекшас
Несколько особенностей: (1) Он использует массивы NumPy. (2) Он написан с использованием только python и numpy, поэтому он не требует установки библиотеки C. (3) Он может создавать анимированные файлы PNG. (4) Он предоставляет класс для написания анимаций matplotlib в виде анимированных файлов PNG.
Уоррен Векессер
Спасибо! Мне было бы любопытно, как это сравнивается с stackoverflow.com/a/19174800/981933 с точки зрения производительности, которая также является чистым Python. Первый метод выше в 2 раза быстрее, чем PIL, что довольно круто. Не
бери в голову,
2

Предполагая, что вы хотите изображение в градациях серого:

im = Image.new('L', (width, height))
im.putdata(an_array.flatten().tolist())
im.save("image.tiff")
Гийом Лебретон
источник
2

ImageIO - это библиотека Python, которая предоставляет простой интерфейс для чтения и записи широкого спектра данных изображений, включая анимированные изображения, видео, объемные данные и научные форматы. Он кроссплатформенный, работает на Python 2.7 и 3.4+ и прост в установке.

Это пример для изображения в градациях серого:

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

Если вы уже используете [Py] Qt, вас может заинтересовать qimage2ndarray . Начиная с версии 1.4 (только что выпущенной), PySide также поддерживается, и будет небольшая imsave(filename, array)функция, похожая на scipy, но использующая Qt вместо PIL. С 1.3 просто используйте что-то вроде следующего:

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

(Еще одним преимуществом 1.4 является то, что это чисто Python-решение, что делает его еще более легким.)

hans_meine
источник
Выпуск 1.4 уже вышел. :-) (Я соответственно отредактировал ответ.)
hans_meine
1

Если вы работаете в среде Python Spyder, то это не может быть проще, чем просто щелкнуть правой кнопкой мыши массив в проводнике переменных, а затем выбрать параметр Показать изображение.

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

Это попросит вас сохранить изображение в dsik, в основном в формате PNG.

Библиотека PIL в этом случае не понадобится.

abunickabhi
источник
1

Использование 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  
Кристи Ли
источник
1

для сохранения массива в виде изображения у вас есть несколько вариантов:

1) лучший из других: OpenCV

 import cv2   
 cv2.imwrite('file name with extension(like .jpg)', numpy_array)

2) Матплотлиб

  from matplotlib import pyplot as plt
  plt.imsave('file name with extension(like .jpg)', numpy_array)

3) ПИЛ

  from PIL import Image
  image = Image.fromarray(numpy_array)
  image.save('file name with extension(like .jpg)')

4) ...

Нима Фархади
источник