Lưu một mảng Numpy dưới dạng hình ảnh


260

Tôi có một ma trận theo kiểu mảng Numpy. Làm thế nào tôi có thể viết nó vào đĩa như một hình ảnh? Mọi định dạng đều hoạt động (png, jpeg, bmp ...). Một hạn chế quan trọng là PIL không có mặt.


12
Tôi chỉ muốn lưu ý rằng một số câu trả lời dưới đây, và chắc chắn một số người đến và tìm thấy câu hỏi này, không đáp ứng các ràng buộc được liệt kê ở trên về việc không có PIL . Vì một số người hỏi và một số câu trả lời đều tránh được sự hạn chế đó, tôi khuyến khích bất kỳ ai ở đây và không bận tâm đến việc PIL nhìn bên dưới, và bất kỳ câu trả lời không phải PIL nào (mới hoặc cũ) đều đề cập rằng chúng là PIL được sử dụng loại câu trả lời, để phân biệt với câu trả lời đáp ứng các ràng buộc ban đầu.
lindes

Câu trả lời:


54

Bạn có thể sử dụng PyPNG . Đó là một bộ mã hóa / giải mã PNG mã nguồn mở thuần túy (không phụ thuộc) và nó hỗ trợ viết các mảng NumPy dưới dạng hình ảnh.


4
Hãy nhớ chia tỷ lệ các giá trị thành phạm vi phù hợp cho PNG, thường là 0..255. Phạm vi giá trị trong các mạng thần kinh thường là 0..1 hoặc -1..1.
Tomáš Gavenčiak

8
PyPNG là Python thuần túy, làm giảm các phụ thuộc bên ngoài của nó, nhưng làm cho nó chậm hơn nhiều so với PIL và các lớp dẫn xuất của nó. Ví dụ: lưu hình ảnh 3000x4000 trên máy của tôi mất 4,05 giây với PyPNG nhưng chỉ 0,59 giây với scipy.misc.imsave (nhanh hơn 6 lần).
Zvika

@ TomášGavenčiak - scipy.misc.imsave hiện không được chấp nhận trong các phiên bản mới hơn của Scipy. Một vài ý kiến ​​khác dưới đây là sử dụng imageio.imwrite ('image_file.jpg', mảng)
Psi-Ed

259

Cái này sử dụng PIL, nhưng có lẽ một số có thể thấy nó hữu ích:

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

EDIT : scipyPhiên bản hiện tại bắt đầu bình thường hóa tất cả các hình ảnh để min (dữ liệu) trở thành màu đen và max (dữ liệu) trở thành màu trắng. Điều này là không mong muốn nếu dữ liệu phải là mức xám chính xác hoặc các kênh RGB chính xác. Giải pháp:

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

19
imsave sống trong ... / scipy / misc / pilutil.py sử dụng PIL
denis

5
Hãy cẩn thận khi chuyển đổi sang jpg vì nó bị mất và do đó bạn không thể khôi phục dữ liệu chính xác được sử dụng để tạo hình ảnh.
Feanil

8
Điều này hiện không được chấp nhận trong việc sử dụng scipy 0.19 - scipy.io.imwrite
g.stevo

6
"Imsave không được dùng nữa trong SciPy 1.0.0 và sẽ bị xóa trong 1.2.0" ( tài liệu Scipy 1.1.0 )
noobar

15
scipy.misc.imsave không được dùng nữa. sử dụng nhập hình ảnh; imageio.imwrite ('file_name.jpg', nmupy_array)
ChaosPredictor

228

Một câu trả lời bằng PIL (chỉ trong trường hợp nó hữu ích).

đưa ra một mảng numpy "A":

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

bạn có thể thay thế "jpeg" bằng hầu hết mọi định dạng bạn muốn. Chi tiết hơn về các định dạng ở đây


5
Hình ảnh là một mô-đun của PIL. Làm "in Ảnh .__ file__"
Juh_

10
Rất hữu ích cho những người trong chúng ta lang thang ở đây và có PIL - Tôi nghĩ rằng tôi sẽ sử dụng from PIL import Imageđể làm cho nó rõ ràng ...
hiền nhân

4
Nếu bạn đã có một hình ảnh RGB, bạn có thể lấy hình ảnh sử dụng im = Image.fromarray (A) .convert ( 'RGB') Thông tin thêm: stackoverflow.com/questions/4711880/...
Roger Veciana

Sử dụng trục thứ ba của một mảng uint8 để mã RGB hoạt động với phương thức này. Mô-đun PIL có thể được cài đặt bằng cách sử dụng "gối cài đặt pip".
bli

1
@Ludovico Verniani Nó không làm biến dạng hình ảnh, nhưng nó sử dụng mã hóa màu hơi phổ biến trong đó thứ tự của các màu là BGR thay vì RGB.
Zvika

88

Với matplotlib:

import matplotlib

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

Hoạt động với matplotlib 1.3.1, tôi không biết về phiên bản thấp hơn. Từ chuỗi tài liệu:

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.

nhập mô tả hình ảnh ở đây


Sử dụng cái này. Nhưng bị rò rỉ bộ nhớ
SolessChong

matplotlib.imsave () trong các phiên bản mới hơn
Vinay Lodha

6
Đó là matplotlib.pyplot.imsavetrong matplotlib 2+
Aleksei Petrenko

1
@HughPerkins thử dùng gối thay thế PIL trong Python 3
christianbrodbeck

10
import matplotlib.pyplot as pltvà sau đóplt.imsave('name.png', array)
Alessandro Jacopson

61

Python thuần túy (2 & 3), một đoạn không có sự phụ thuộc của bên thứ 3.

Hàm này ghi RGBAPNG , màu sắc trung thực (4 byte cho mỗi pixel) .

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

... Dữ liệu phải được ghi trực tiếp vào tệp được mở dưới dạng nhị phân, như trong:

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


2
Đây có vẻ là chính xác những gì tôi đang tìm kiếm, nhưng bạn có thể thêm một số ý kiến? Tôi không thấy cách này ghi vào một tập tin. Bạn có phải viết đầu ra trong một tập tin đã mở trước đó? Cảm ơn!
PhilMacKay

1
@PhilMacKay, dữ liệu chỉ cần được ghi vào tệp nhị phân. thêm bình luận.
ideaman42

1
Ai đó có thể chỉ định định dạng mà hình ảnh ( buf) được cho là ở trong không? Nó dường như không phải là một mảng khó chịu ...
christianbrodbeck

1
@christianmbrodbeck, một phụ bản (RGBARGBA ...)
ideaman42

1
Cảm ơn @ ideaman42. Tôi đã chuyển mã này để sử dụng trong Blender .
emackey

57

opencvcho python ( tài liệu ở đây ).

import cv2
import numpy as np

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

hữu ích nếu bạn cần xử lý nhiều hơn ngoài việc tiết kiệm.


1
Tại sao mảng cỡ 10? Điều gì dẫn đến sự lựa chọn 10 được sử dụng trong giải pháp này?
Gathide

3
@Gathide Chỉ là một ví dụ về việc viết một số ma trận numpy tùy ý vào tệp. Trong cuộc sống thực thay thế np.zeros((10,10))bằng hình ảnh của bạn.
Xocoatzin

5
Làm cách nào tôi có thể thêm một cái gì đó giống như cmap="gray"khi tôi lưu hình ảnh bằng cv2?
Mona Jalal

@Xocoatzin Liên kết bị hỏng?
jtlz2

1
@ jtlz2 Liên kết cập nhật.
Xocoatzin

30

Nếu bạn có matplotlib, bạn có thể làm:

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

Điều này sẽ lưu cốt truyện (không phải hình ảnh chính nó). nhập mô tả hình ảnh ở đây


10
Không, đối với giao diện pyplot, plt.figure () là không cần thiết. Ngoài ra, bạn chỉ cần plt.show () nếu bạn muốn xem cửa sổ hình - trong trường hợp này chỉ lưu tệp hình ảnh là mong muốn, do đó không cần phải gọi show ().
DopplerShift

7
Lưu ý rằng tệp hình ảnh thu được sẽ chứa các trục và vùng màu xám của hình matlplotlib - không chỉ dữ liệu pixel.
Dave

1
sẽ không hoạt động nếu bạn chạy tập lệnh của bạn trên máy chủ từ xa, ssh-ing cho nó mà không hỗ trợ giao diện đồ họa.
Temak

Nếu bạn muốn hiển thị hình ảnh trong sổ ghi chép, bạn có thể thêm vào như sau: >> "từ IPython.display nhập hình ảnh" và sau đó >> "Hình ảnh (tên tệp = tên tệp)"
Robert

Để xóa trục:plt.axis('off')
yakout 22/12/18

15

Bạn có thể sử dụng thư viện 'skimage' trong Python

Thí dụ:

from skimage.io import imsave
imsave('Path_to_your_folder/File_name.jpg',your_array)

15

scipy.miscđưa ra cảnh báo khấu hao về imsavechức năng và đề nghị sử dụng imageiothay thế.

import imageio
imageio.imwrite('image_name.png', img)

12

Phụ lục cho câu trả lời của @ ideaman42:

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

Vì vậy, bạn có thể làm:

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

Sản xuất test_grid.png:

Lưới màu đỏ, vàng, xanh đậm, xám

(Tính minh bạch cũng hoạt động, bằng cách giảm byte cao từ 0xff.)


8

Đối với những người tìm kiếm một ví dụ làm việc trực tiếp đầy đủ:

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

Ngoài ra, nếu bạn muốn jpeg chất lượng cao
.save(file, subsampling=0, quality=100)


6

matplotlib svn có một chức năng mới để lưu hình ảnh chỉ là một hình ảnh - không có trục, v.v ... đó là một chức năng rất đơn giản để backport, nếu bạn không muốn cài đặt svn (được sao chép trực tiếp từ image.py trong matplotlib svn, hãy xóa doc Chuỗi cho ngắn gọn):

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

Thế giới có lẽ không cần một gói nào khác để viết một mảng gọn gàng vào một tệp PNG, nhưng đối với những người không thể có đủ, gần đây tôi đã đưa lên numpngwgithub:

https://github.com/WarrenWeckesser/numpngw

và trên pypi: https://pypi.python.org/pypi/numpngw/

Sự phụ thuộc bên ngoài duy nhất là numpy.

Đây là ví dụ đầu tiên từ examplesthư mục của kho lưu trữ. Dòng thiết yếu chỉ đơn giản là

write_png('example1.png', img)

nơi imglà một mảng NumPy. Tất cả mã trước dòng đó là nhập câu lệnh và mã để tạo 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)

Đây là tệp PNG mà nó tạo:

example1.png


Tôi tò mò, lib của bạn khác với những người khác như thế nào? Có nhanh hơn không? Liệu nó có các tính năng ưa thích?
F Lekschas

Một vài tính năng: (1) Nó sử dụng mảng numpy. (2) Nó được viết chỉ bằng python và numpy, vì vậy nó không yêu cầu cài đặt thư viện C. (3) Nó có thể tạo các tệp PNG hoạt hình. (4) Nó cung cấp một lớp để viết hoạt hình matplotlib dưới dạng tệp PNG hoạt hình.
Warren Weckesser

Cảm ơn! Tôi tò mò làm thế nào nó so sánh với stackoverflow.com/a/19174800/981933 về hiệu suất cũng là con trăn thuần túy. Phương pháp trước đây nhanh hơn gấp 2 lần so với PIL, khá tuyệt vời. Đừng bận tâm nếu đó không phải là mục tiêu của bạn :)
F Lekschas

2

Giả sử bạn muốn có một hình ảnh thang độ xám:

im = Image.new('L', (width, height))
im.putdata(an_array.flatten().tolist())
im.save("image.tiff")

2

Imageio là một thư viện Python cung cấp giao diện dễ đọc và ghi nhiều loại dữ liệu hình ảnh, bao gồm hình ảnh hoạt hình, video, dữ liệu thể tích và các định dạng khoa học. Nó là đa nền tảng, chạy trên Python 2.7 và 3.4+ và rất dễ cài đặt.

Đây là ví dụ cho hình ảnh thang độ xám:

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

Nếu bạn tình cờ sử dụng [Py] Qt, bạn có thể quan tâm đến qimage2ndarray . Bắt đầu với phiên bản 1.4 (vừa được phát hành), PySide cũng được hỗ trợ và sẽ có một imsave(filename, array)chức năng nhỏ tương tự như scipy, nhưng sử dụng Qt thay vì PIL. Với 1.3, chỉ cần sử dụng một cái gì đó như sau:

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

(Một ưu điểm khác của 1.4 là nó là một giải pháp python thuần, làm cho nó thậm chí còn nhẹ hơn.)


Bản phát hành 1.4 đã ra mắt. :-) (Tôi đã chỉnh sửa câu trả lời tương ứng.)
hans_meine

1

Nếu bạn đang làm việc trong môi trường python Spyder, thì nó không thể dễ dàng hơn là chỉ cần nhấp chuột phải vào mảng trong trình thám hiểm biến, sau đó chọn tùy chọn Hiển thị hình ảnh.

nhập mô tả hình ảnh ở đây

Điều này sẽ yêu cầu bạn lưu hình ảnh vào dsik, chủ yếu ở định dạng PNG.

Thư viện PIL sẽ không cần thiết trong trường hợp này.


1

Sử dụng 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

để lưu một mảng numpy như hình ảnh, U có một số lựa chọn:

1) tốt nhất khác: OpenCV

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

2) Matplotlib

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

3) PIL

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

4) ...

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.