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


261

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


12
Я просто хотел бы отметить, что некоторые из ответов ниже, и, конечно, некоторые из людей, которые приходят и находят этот вопрос, не соответствуют указанному выше ограничению - быть без PIL . Поскольку некоторые спрашивающие и некоторые ответы оба избегают этого ограничения, я призываю всех, кто здесь, и не возражает против того, чтобы PIL смотрел ниже, и любые не-PIL ответы (новые или старые), чтобы упомянуть, что они используются PIL. тип ответа, чтобы отличить себя от ответов, отвечающих первоначальному ограничению.
Линд

Ответы:


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.

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


Используя это. Но страдает от утечки памяти
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)


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

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


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)

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-решение, что делает его еще более легким.)


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

1

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

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

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

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


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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.