Can I save a numpy array as a 16-bit image using "normal" (Enthought) python?
One alternative is to use pypng. You'll still have to install another package, but it is pure Python, so that should be easy. (There is actually a Cython file in the pypng source, but its use is optional.)
Here's an example of using pypng to write numpy arrays to PNG:
import png
import numpy as np
# The following import is just for creating an interesting array
# of data. It is not necessary for writing a PNG file with PyPNG.
from scipy.ndimage import gaussian_filter
# Make an image in a numpy array for this demonstration.
nrows = 240
ncols = 320
np.random.seed(12345)
x = np.random.randn(nrows, ncols, 3)
# y is our floating point demonstration data.
y = gaussian_filter(x, (16, 16, 0))
# Convert y to 16 bit unsigned integers.
z = (65535*((y - y.min())/y.ptp())).astype(np.uint16)
# Use pypng to write z as a color PNG.
with open('foo_color.png', 'wb') as f:
writer = png.Writer(width=z.shape[1], height=z.shape[0], bitdepth=16)
# Convert z to the Python list of lists expected by
# the png writer.
z2list = z.reshape(-1, z.shape[1]*z.shape[2]).tolist()
writer.write(f, z2list)
# Here's a grayscale example.
zgray = z[:, :, 0]
# Use pypng to write zgray as a grayscale PNG.
with open('foo_gray.png', 'wb') as f:
writer = png.Writer(width=z.shape[1], height=z.shape[0], bitdepth=16, greyscale=True)
zgray2list = zgray.tolist()
writer.write(f, zgray2list)
Here's the color output:
and here's the grayscale output:
Update: I created a library called numpngw
(available on PyPI
and github
) that provides a function for writing a numpy array to a PNG file. The repository has a setup.py
file for installing it as a package, but the essential code is in a single file, numpngw.py
, that could be copied to any convenient location. The only dependency of numpngw
is numpy.
Here's a script that generates the same 16 bit images as those shown above:
import numpy as np
import numpngw
# The following import is just for creating an interesting array
# of data. It is not necessary for writing a PNG file.
from scipy.ndimage import gaussian_filter
# Make an image in a numpy array for this demonstration.
nrows = 240
ncols = 320
np.random.seed(12345)
x = np.random.randn(nrows, ncols, 3)
# y is our floating point demonstration data.
y = gaussian_filter(x, (16, 16, 0))
# Convert y to 16 bit unsigned integers.
z = (65535*((y - y.min())/y.ptp())).astype(np.uint16)
# Use numpngw to write z as a color PNG.
numpngw.write_png('foo_color.png', z)
# Here's a grayscale example.
zgray = z[:, :, 0]
# Use numpngw to write zgray as a grayscale PNG.
numpngw.write_png('foo_gray.png', zgray)
Save numpy array as image with high precision (16 bits) with scikit-image
You wanna use the freeimage
library to do so:
import numpy as np
from skimage import io, exposure, img_as_uint, img_as_float
io.use_plugin('freeimage')
im = np.array([[1., 2.], [3., 4.]], dtype='float64')
im = exposure.rescale_intensity(im, out_range='float')
im = img_as_uint(im)
io.imsave('test_16bit.png', im)
im2 = io.imread('test_16bit.png')
Result:
[[ 0 21845]
[43690 65535]]
As for 3D arrays, you need to construct the array properly and then it'll work:
# im = np.array([[1, 2.], [3., 4.]], dtype='float64')
im = np.linspace(0, 1., 300).reshape(10, 10, 3)
im = exposure.rescale_intensity(im, out_range='float')
im = img_as_uint(im)
io.imsave('test_16bit.png', im)
im2 = io.imread('test_16bit.png')
Note that the read image is flipped, so something like np.fliplr(np.flipud(im2))
will bring it to original shape.
How to Stack N number of 2D arrays as an image together
You can write a (22,5,3884) array of float32
to a TIFF like this:
import tifffile
import numpy as np
# Synthesize image
signals = np.zeros((22,5,3844), dtype=np.float32)
# Save as TIFF
tifffile.imwrite('signals.tif', signals)
If you check the result with tiffinfo
:
tiffinfo signals.tif
you can see there are 22 images in the file, each one a 3844x5 greyscale image of 32-bit IEEE-754 floating point.
Sample Output
TIFF Directory at offset 0x8 (8)
Image Width: 3844 Image Length: 5
Resolution: 1, 1 (unitless)
Bits/Sample: 32
Sample Format: IEEE floating point
Compression Scheme: None
Photometric Interpretation: min-is-black
Samples/Pixel: 1
Rows/Strip: 5
Planar Configuration: single image plane
ImageDescription: {"shape": [22, 5, 3844]}
Software: tifffile.py
TIFF Directory at offset 0x19d020 (1691680)
... abbreviated, but as above ...
TIFF Directory at offset 0x19d0d2 (1691858)
... abbreviated, but as above ...
TIFF Directory at offset 0x19d184 (1692036)
... abbreviated, but as above ...
TIFF Directory at offset 0x19d236 (1692214)
TIFF Directory at offset 0x19d2e8 (1692392)
TIFF Directory at offset 0x19d39a (1692570)
TIFF Directory at offset 0x19d44c (1692748)
TIFF Directory at offset 0x19d4fe (1692926)
TIFF Directory at offset 0x19d5b0 (1693104)
TIFF Directory at offset 0x19d662 (1693282)
TIFF Directory at offset 0x19d714 (1693460)
TIFF Directory at offset 0x19d7c6 (1693638)
TIFF Directory at offset 0x19d878 (1693816)
TIFF Directory at offset 0x19d92a (1693994)
TIFF Directory at offset 0x19d9dc (1694172)
TIFF Directory at offset 0x19da8e (1694350)
TIFF Directory at offset 0x19db40 (1694528)
TIFF Directory at offset 0x19dbf2 (1694706)
TIFF Directory at offset 0x19dca4 (1694884)
TIFF Directory at offset 0x19dd56 (1695062)
TIFF Directory at offset 0x19de08 (1695240)
If you want the signals stacked one-above-the-other vertically, you can reshape()
like this:
tifffile.imwrite('signals.tif', signals.reshape(110,3844))
I made each of the 22 sub-images a solid grey that increases down the stack so you can see the image is dark at the top and light at the bottom:
Convert back to 2D numpy array from .jpg image
If your objective is to save a numpy array as an image, your approach have a problem. The function plt.savefig
saves an image of the plot, not the array. Also transforming an array into an image may carry some precision loss (when converting from float64
or float32
to uint16
). That been said, I suggest you use skimage and imageio:
import imageio
import numpy as np
from skimage import img_as_uint
data = np.load('0058_00086_brown_2_recording1.wav.npy')
print("original", data.shape)
img = img_as_uint(data)
imageio.imwrite('image.png', img)
load = imageio.imread('image.png')
print("image", load.shape)
This script loads the data you provided and prints the shape for verification
data = np.load('0058_00086_brown_2_recording1.wav.npy')
print("original", data.shape)
then it transform the data
to uint
, saves the image as png and loads it:
img = img_as_uint(data)
imageio.imwrite('image.png', img)
load = imageio.imread('image.png')
the output of the script is:
original (64, 25)
image (64, 25)
i.e. the image is loaded with the same shape that data. Some notes:
- image.png is saved as a grayscale image
- To save to .jpg just change to
imageio.imwrite('image.jpg', img)
- In the case of .png the absolute average distance from the original image was
3.890e-06
(this can be verified usingnp.abs(img_as_float(load) - data).sum() / data.size
)
Information about skimage and imageio can be found in the respectives websites. More on saving numpy arrays as images can be found in the following answers: [1], [2], [3] and [4].
scipy: savefig without frames, axes, only content
EDIT
Changed aspect='normal
to aspect='auto'
since that changed in more recent versions of matplotlib (thanks to @Luke19).
Assuming :
import matplotlib.pyplot as plt
To make a figure without the frame :
fig = plt.figure(frameon=False)
fig.set_size_inches(w,h)
To make the content fill the whole figure
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
Then draw your image on it :
ax.imshow(your_image, aspect='auto')
fig.savefig(fname, dpi)
The aspect
parameter changes the pixel size to make sure they fill the figure size specified in fig.set_size_inches(…)
. To get a feel of how to play with this sort of things, read through matplotlib's documentation, particularly on the subject of Axes, Axis and Artist.
Related Topics
How to Find the Average of Particular Numbers in a CSV File
Google Chrome Closes Immediately After Being Launched With Selenium
How to Convert an Integer to Time
How to Assign and Use Column Headers in Spark
Filtering Date Column in Python
Stored Procedures With Sqlalchemy
Pyodbc Error Data Source Name Not Found and No Default Driver Specified Paradox
How to Merge Two Cnn That Are Trained Over Different Data Stream
How to Display a Plot in Fullscreen
How to Change Dd-Mm-Yyyy Date Format to Yyyy-Dd-Mm in Pandas
Python Serial: How to Use the Read or Readline Function to Read More Than 1 Character At a Time
How to Replace Nan Values Where the Other Columns Meet a Certain Criteria
How to Convert a Pandas Dataframe to a Pytorch Tensor
Pandas Update and Add Rows One Dataframe With Key Column in Another Dataframe
Find Matching Rows in 2 Dimensional Numpy Array
Removing Punctuations and Spaces in a String Without Using Regex
Pyside - Pyqt:How to Make Set Qtablewidget Column Width as Proportion of the Available Space