I have a matrix in the type of a Numpy array. How would I write it to disk it as an image? Any format works (png, jpeg, bmp...). One important constraint is that PIL is not present.
-
20I'd just like to note that some of the answers below, and surely some of the people coming and finding this question, do not meet the constraint listed above of being without PIL. Since some askers and some answers both avoid that constraint, I encourage anyone who's here and doesn't mind having PIL to look below, and any non-PIL answers (new or old) to mention that they're a PIL-is-used type of answer, to distinguish themselves from answers meeting the original constraint.lindes– lindes2013-10-30 15:46:18 +00:00Commented Oct 30, 2013 at 15:46
-
Seems related: stackoverflow.com/questions/33480297/viewing-npy-imageshola– hola2020-05-15 20:51:46 +00:00Commented May 15, 2020 at 20:51
24 Answers
Using PIL, save a NumPy array arr by doing:
from PIL import Image
im = Image.fromarray(arr)
im.save("your_file.jpeg")
See the docs for available data formats, including JPEG, PNG, and so on.
12 Comments
from PIL import Image to keep it clear...This uses PIL, but maybe some might find it useful:
import scipy.misc
scipy.misc.imsave('outfile.jpg', image_array)
EDIT: The current scipy version started to normalize all images so that min(data) become black and max(data) become white. This is unwanted if the data should be exact grey levels or exact RGB channels. The solution:
import scipy.misc
scipy.misc.toimage(image_array, cmin=0.0, cmax=...).save('outfile.jpg')
13 Comments
With matplotlib:
import matplotlib.image
matplotlib.image.imsave('name.png', array)
Works with matplotlib 1.3.1, I don't know about lower version. From the 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.
6 Comments
matplotlib.pyplot.imsave in matplotlib 2+import matplotlib.pyplot as plt and then plt.imsave('name.png', array)There's opencv for python (documentation here).
import cv2
import numpy as np
img = ... # Your image as a numpy array
cv2.imwrite("filename.png", img)
useful if you need to do more processing other than saving.
6 Comments
np.zeros((10,10)) with your image.cmap="gray" for when I save the image using cv2?Pure Python (2 & 3), a snippet without 3rd party dependencies.
This function writes compressed, true-color (4 bytes per pixel) RGBA PNG's.
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'')])
... The data should be written directly to a file opened as binary, as in:
data = write_png(buf, 64, 64)
with open("my_image.png", 'wb') as fh:
fh.write(data)
- Original source
- See also: Rust Port from this question.
- Example usage thanks to @Evgeni Sergeev: https://stackoverflow.com/a/21034111/432509
6 Comments
buf) is supposed to be in? It does not seem to be a numpy array...You can use PyPNG. It's a pure Python (no dependencies) open source PNG encoder/decoder and it supports writing NumPy arrays as images.
3 Comments
for saving a numpy array as image, you have several choices:
- best of other: OpenCV
import cv2 cv2.imwrite('file name with extension(like .jpg)', numpy_array)
- Matplotlib
from matplotlib import pyplot as plt plt.imsave('file name with extension(like .jpg)', numpy_array)
- PIL
from PIL import Image image = Image.fromarray(numpy_array) image.save('file name with extension(like .jpg)')
- ...
1 Comment
from PIL import Image is a clear winner in terms of time it takes to load the module.If you have matplotlib, you can do:
import matplotlib.pyplot as plt
plt.imshow(matrix) #Needs to be in row,col order
plt.savefig(filename)
7 Comments
plt.axis('off')Addendum to @ideasman42's answer:
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()
So you can do:
saveAsPNG([[0xffFF0000, 0xffFFFF00],
[0xff00aa77, 0xff333333]], 'test_grid.png')
Producing test_grid.png:

(Transparency also works, by reducing the high byte from 0xff.)
Comments
For those looking for a direct fully working example:
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
also, if you want high quality jpeg's
.save(file, subsampling=0, quality=100)
Comments
matplotlib svn has a new function to save images as just an image -- no axes etc. it's a very simple function to backport too, if you don't want to install svn (copied straight from image.py in matplotlib svn, removed the docstring for brevity):
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)
Comments
Imageio is a Python library that provides an easy interface to read and write a wide range of image data, including animated images, video, volumetric data, and scientific formats. It is cross-platform, runs on Python 2.7 and 3.4+, and is easy to install.
This is example for grayscale image:
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)
Comments
The world probably doesn't need yet another package for writing a numpy array to a PNG file, but for those who can't get enough, I recently put up numpngw on github:
https://github.com/WarrenWeckesser/numpngw
and on pypi: https://pypi.python.org/pypi/numpngw/
The only external dependency is numpy.
Here's the first example from the examples directory of the repository. The essential line is simply
write_png('example1.png', img)
where img is a numpy array. All the code before that line is import statements and code to create 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)
Here's the PNG file that it creates:
Also, I used numpngw.write_apng to create the animations in Voronoi diagram in Manhattan metric.
3 Comments
In the following answer has the methods as proposed by @Nima Farhadi in time measurement.
The fastest is CV2 , but it's important to change colors order from RGB to BGR. The simplest is matplotlib.
It's important to assure, that the array have unsigned integer format uint8/16/32.
Code:
#Matplotlib
from matplotlib import pyplot as plt
plt.imsave('c_plt.png', c.astype(np.uint8))
#PIL
from PIL import Image
image = Image.fromarray(c.astype(np.uint8))
image.save('c_pil.png')
#CV2, OpenCV
import cv2
cv2.imwrite('c_cv2.png', cv2.cvtColor(c, cv2.COLOR_RGB2BGR))
Comments
If you happen to use [Py]Qt already, you may be interested in qimage2ndarray. Starting with version 1.4 (just released), PySide is supported as well, and there will be a tiny imsave(filename, array) function similar to scipy's, but using Qt instead of PIL. With 1.3, just use something like the following:
qImage = array2qimage(image, normalize = False) # create QImage from ndarray
success = qImage.save(filename) # use Qt's image IO functions for saving PNG/JPG/..
(Another advantage of 1.4 is that it is a pure python solution, which makes this even more lightweight.)
1 Comment
With pygame
so this should work as I tested (you have to have pygame installed if you do not have pygame install it by using pip -> pip install pygame (that sometimes does not work so in that case you will have to download the wheel or sth but that you can look up on google)):
import pygame
pygame.init()
win = pygame.display.set_mode((128, 128))
pygame.surfarray.blit_array(win, yourarray)
pygame.display.update()
pygame.image.save(win, 'yourfilename.png')
just remember to change display width and height according to your array
here is an example, run this code:
import pygame
from numpy import zeros
pygame.init()
win = pygame.display.set_mode((128, 128))
striped = zeros((128, 128, 3))
striped[:] = (255, 0, 0)
striped[:, ::3] = (0, 255, 255)
pygame.surfarray.blit_array(win, striped)
pygame.display.update()
pygame.image.save(win, 'yourfilename.png')
Comments
You can use this code for converting your Npy data into an image by using the PIL python library as this library mainly deal with images as well as here, I've used numpy to load the image format in the context of the dataset:
#importing the libraries
from PIL import Image
import numpy as np
data = np.load('/kaggle/input/objects-dataset/nmbu.npy')
im = Image.fromarray(data, 'RGB')
#saving the image from the npy format
im.save("your_file.jpeg")
2 Comments
Building on @ideasman42's answer and Evgeni Sergeev's addendum, here is an implementation to convert numpy arrays to images.
Note: this implementation puts a[1,1,:] in the top left of the image
To demystify the png format, I pasted some info from http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html
this implementation displays:
- nxm arrays using a palette and scaling the values
- nxmx3 RGB arrays with one transparency color; ignores palette
- nxmx4 RGBA arrays; ignores palette and transparent color
it returns a byte string that can be passed to a PhotoImage. It's not a rigorous as Warren Weckesser' writepng below, but it gets the data into tkinter in a transparent manner.
# https://stackoverflow.com/questions/902761/saving-a-numpy-array-as-an-image
# http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html
# we insist on
# o values between 0-1
# o g, ga, rgb, rgba
# o nxmx 1/2/3/3
import numpy as np
import zlib, struct
def topngbytes(a:np.ndarray,transparentcolor=[1,2,3],hicolor=[255,95,0]):
sz = a.shape
lensz=len(sz)
height,width=sz[0:2]
colortype=0
palette=None
# Color Allowed Interpretation
# Type Bit Depths
#
# 0 1,2,4,8,16 Each pixel is a grayscale sample.
# 2 8,16 Each pixel is an R,G,B triple.
# 3 1,2,4,8 Each pixel is a palette index;
# a PLTE chunk must appear.
# 4 8,16 Each pixel is a grayscale sample,
# followed by an alpha sample.
# 6 8,16 Each pixel is an R,G,B triple,
# followed by an alpha sample.
if lensz==2:
colortype=3 # 8bit palette
amin=np.min(a)
da=np.max(a)-amin
if da==0: a=a*0+127
elif da<72 or da>255: a=255/da*(a-amin)
cmin = np.array(transparentcolor,dtype=float) # generate a two tone palette
dc = hicolor - cmin
palette = np.zeros(shape=(256, 3), dtype=np.uint8)
for i, r in enumerate(palette): r[:] = cmin + dc/255. * i
elif lensz==3:
n=sz[-1] #color info always the last dimension
if n==2: colortype=4 # grey+alpha
elif n==3: colortype=2 # rgb
elif n==4: colortype=6 # rgba
else: raise(ValueError(f"mImg: color dimension must be nxmx 1,2,3 or 4, not {sz}"))
buf = b''.join( b'\x00' + row.tobytes() for row in a.astype(dtype=np.uint8))
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))
# first chunc is IHDR
# Width: 4 bytes
# Height: 4 bytes
# Bit depth: 1 byte --> we use 8 = 0-255
# Color type: 1 byte
# Compression method: 1 byte
# Filter method: 1 byte
# Interlace method: 1 byte
# The PLTE chunk contains from 1 to 256 palette entries, each a three-byte series of the form:
#
# Red: 1 byte (0 = black, 255 = red)
# Green: 1 byte (0 = black, 255 = green)
# Blue: 1 byte (0 = black, 255 = blue)
# The number of entries is determined from the chunk length. A chunk length not divisible by 3 is an error.
#
# This chunk must appear for color type 3, and can appear for color types 2 and 6;
# it must not appear for color types 0 and 4. If this chunk does appear, it must precede the first IDAT chunk.
# There must not be more than one PLTE chunk.
#
# For color type 3 (indexed color), the PLTE chunk is required.
# The first entry in PLTE is referenced by pixel value 0
IHDR=png_pack(b'IHDR', struct.pack("!2I5B", width, height, 8, colortype, 0, 0, 0))
PLTE = b'' if (colortype in [0,4]) or palette is None else png_pack(b'PLTE',palette.tobytes())
t=transparentcolor
tRNS = png_pack(b'tRNS', struct.pack("!6B", t[0], 0, t[1], 0, t[2], 0))
IDAT = png_pack(b'IDAT', zlib.compress(buf, 9))
IEND = png_pack(b'IEND', b'')
return b''.join([b'\x89PNG\r\n\x1a\n',IHDR,PLTE,tRNS,IDAT,IEND])




