Збереження масиву Numpy як зображення


260

У мене є матриця типу масиву Numpy. Як би я записав це на диск, як зображення? Будь-який формат працює (png, jpeg, bmp ...). Одне важливе обмеження полягає в тому, що PIL відсутній.


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

Відповіді:


54

Можна використовувати PyPNG . Це чистий датчик / декодер PNG з відкритим кодом Python (без залежностей) і він підтримує запис масивів NumPy у вигляді зображень.


4
Не забудьте масштабувати значення до потрібного діапазону для PNG, як правило, 0..255. Діапазони значень у нейронних мережах часто становлять 0..1 або -1..1.
Томаш Гавенчіак

8
PyPNG - це чистий Python, який зменшує його зовнішні залежності, але робить його набагато повільніше, ніж PIL та його похідні класи. Наприклад, збереження зображення на 3000х4000 на моїй машині зайняло 4,05 секунди за допомогою PyPNG, але лише 0,59 секунди за допомогою scipy.misc.imsave (на 6 разів швидше).
Звіка

@ TomášGavenčiak - scipy.misc.imsave тепер застарілий у нових версіях Scipy. Альтернативою декількох коментарів нижче є використання imageio.imwrite ('image_file.jpg', масив)
Psi-Ed

259

Для цього використовується PIL, але, можливо, деякі можуть вважати його корисним:

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

EDIT : Поточна scipyверсія почала нормалізувати всі зображення, щоб хв (дані) стали чорними, а макс (дані) - білими. Це небажано, якщо дані мають бути точними рівнями сірого чи точними каналами RGB. Рішення:

import scipy.misc
scipy.misc.toimage(image_array, cmin=0.0, cmax=...).save('outfile.jpg')

19
imsave живе в ... / SciPy / різне / 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 (про всяк випадок, коли це корисно).

задано нумерований масив "A":

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 зображення, ви можете отримати зображення з допомогою їм = Image.fromarray (A) .convert ( «RGB») Детальніше: stackoverflow.com/questions/4711880 / ...
Roger Veciana

Використання третьої осі масиву uint8 для кодування RGB працює з цим методом. Модуль PIL можна встановити за допомогою "подушки для встановлення".
блі

1
@Ludovico Verniani Він не спотворює зображення, але він використовує дещо незвичне кольорове кодування, в якому порядок кольорів - це BGR, а не RGB.
Zvika

87

З matplotlib:

import matplotlib

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

Працює з matplotlib 1.3.1, про нижню версію я не знаю. З docstring:

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в matplotlib 2+
Олексій Петренко

1
@HughPerkins спробуйте подушку як заміну PIL в Python 3
christianbrodbeck

10
import matplotlib.pyplot as pltа потімplt.imsave('name.png', array)
Алессандро Якопсон

61

Чистий Python (2 і 3), фрагмент без сторонніх залежностей.

Ця функція записує стислі, справжні кольорові (4 байти на піксель) RGBAPNG.

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, дані просто повинні бути записані у двійковий файл. доданий коментар.
ideaman42

1
Хтось може вказати, у якому форматі зображення ( buf) має бути? Здається, це не нудний масив ...
christianbrodbeck

1
@christianmbrodbeck, bytearray (RGBARGBA ...)
ideaman42

1
Дякуємо @ Ideman42. Я переніс цей код для використання в Blender .
emackey

57

Там opencvдля python ( тут документація ).

import cv2
import numpy as np

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

корисно, якщо вам потрібно більше обробити, крім збереження.


1
Чому масив розміром 10? Що призвело до вибору 10 використовуваних у цьому рішенні?
Gathide

3
@Gathide Як приклад написання довільної матриці numpy у файл. У реальному житті замініть np.zeros((10,10))своїм образом.
Xocoatzin

5
Як я можу додати щось на зразок, cmap="gray"коли я зберігаю зображення за допомогою cv2?
Мона Джалал

@Xocoatzin Пошкоджене посилання?
jtlz2

1
@ jtlz2 Оновлено посилання.
Xocoatzin

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 імпортувати зображення", а потім >> "Зображення (ім'я файлу = ім'я файлу)"
Роберт

Для зняття осі: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

Додаток до відповіді @ Ideman42:

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, вилучив docstring для стислості):

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

та на pypi: https://pypi.python.org/pypi/numpngw/

Єдина зовнішня залежність - нумерована.

Ось перший приклад із examplesкаталогу сховища. Істотна лінія просто

write_png('example1.png', img)

де imgнумерований масив. Весь код перед цим рядком - це заяви про імпорт та код для створення 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


Мені цікаво, чим ваша лайка відрізняється від інших? Це швидше? Чи є у нього модні функції?
F Лекшас

Кілька особливостей: (1) Він використовує масивні масиви. (2) Він пишеться за допомогою просто python та numpy, тому для нього не потрібно встановлювати бібліотеку C. (3) Він може створювати анімовані файли PNG. (4) Він містить клас для запису анімації matplotlib у вигляді анімованих файлів PNG.
Warren Weckesser

Дякую! Мені буде цікаво, як вона порівнюється з stackoverflow.com/a/19174800/981933 з точки зору продуктивності, яка також є чистим пітоном. Колишній метод вище в 2 рази швидше, ніж PIL, що досить приголомшливо. Не забувайте, якщо це не ваша мета :)
F Lekschas

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 є те, що це чисте рішення пітона, що робить це ще більш легким.)


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  

0

для збереження масивного масиву як зображення, U має кілька варіантів:

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.