Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read 16-bit PNG image file using Python

I'm trying to read a PNG image file written in 16-bit data type. The data should be converted to a NumPy array. But I have no idea how to read the file in '16-bit'. I tried with PIL and SciPy, but they converted the 16-bit data to 8-bit when they load it. Could anyone please let me know how to read data from a 16-bit PNG file and convert it to NumPy array without changing the datatype?

The following is the script that I used.

from scipy import misc
import numpy as np
from PIL import Image
#make a png file    
a = np.zeros((1304,960), dtype=np.uint16)
a[:] = np.arange(960)
misc.imsave('16bit.png',a)

#read the png file using scipy
b = misc.imread('16bit.png')
print "scipy:" ,b.dtype

#read the png file using PIL
c = Image.open('16bit.png')   
d = np.array(c)
print "PIL:", d.dtype
               
like image 824
Nownuri Avatar asked Sep 17 '15 04:09

Nownuri


2 Answers

I have the same problem here. I tested it even with 16 bit images i created by my own. All of them were opened correctly when i loaded them with the png package. Also the output of 'file ' looked okay.

Opening them with PIL always led to 8-bit numpy-arrays.

Working with Python 2.7.6 on Linux btw.

Like this it works for me:

import png
import numpy as np

reader = png.Reader( path-to-16bit-png )
pngdata = reader.read()
px_array = np.array( map( np.uint16, pngdata[2] ) 
print( px_array.dtype )

Maybe someone can give more information under which circumstances the former approach worked? (as this one is pretty slow)

Thanks in advance.

like image 127
Mr.Fridy Avatar answered Sep 25 '22 12:09

Mr.Fridy


The simplest solution I've found:

When I open a 16 bit monochrome PNG Pillow it doesn't open correctly as I;16 mode. Image.mode is opened as I (32 bits)

So, the best way to convert to numpy array. It is dtype="int32" so we will convert it to dtype="uint16".

import numpy as np
from PIL import Image

im = Image.fromarray(np.array(Image.open(name)).astype("uint16"))
print("Image mode: ", im.mode)

Tested in Python 3.6.8 with Pillow 6.1.0

like image 30
Rutrus Avatar answered Sep 24 '22 12:09

Rutrus