Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I save a numpy array as a 16-bit image using "normal" (Enthought) python?

Tags:

python

numpy

Is there any way to save a numpy array as a 16 bit image (tif, png) using any of the commonly available python packages? This is the only way that I could get to work in the past, but I needed to install the FreeImage package, which is a little annoying.

This seems like a pretty basic task, so I would expect that it should be covered by scipy, but scipy.misc.imsave only does 8-bits.

Any ideas?

like image 215
DanHickstein Avatar asked Sep 06 '14 03:09

DanHickstein


People also ask

How do I save a NumPy array as a picture?

To save the Numpy array as a local image, use the save() function and pass the image filename with the directory where to save it. This will save the Numpy array as a jpeg image.

How do I save a NumPy array to a csv file in Python?

You can save your NumPy arrays to CSV files using the savetxt() function. This function takes a filename and array as arguments and saves the array into CSV format. You must also specify the delimiter; this is the character used to separate each variable in the file, most commonly a comma.

How do I save a 16bit image?

Simply head to Image -> Mode -> 16bit, to convert your Photoshop document to a 16 bit file.

How do I convert NumPy to tensor?

a NumPy array is created by using the np. array() method. The NumPy array is converted to tensor by using tf. convert_to_tensor() method.


2 Answers

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:

foo_color.png

and here's the grayscale output:

foo_gray.png


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)
like image 136
Warren Weckesser Avatar answered Oct 02 '22 19:10

Warren Weckesser


This explanation of png and numpngw is very helpful! But, there is one small "mistake" I thought I should mention. In the conversion to 16 bit unsigned integers, the y.max() should have been y.min(). For the picture of random colors, it didn't really matter but for a real picture, we need to do it right. Here's the corrected line of code...

z = (65535*((y - y.min())/y.ptp())).astype(np.uint16)
like image 22
Robert J. Vanderbei Avatar answered Oct 02 '22 20:10

Robert J. Vanderbei