How can I convert and save a 16 bit single-channel TIF in Python?
I can load a 16 and 32 bit image without an issue, and see that the 32 bit image is mode F
and the 16 bit image is mode I;16S
:
import Image
i32 = Image.open('32.tif')
i16 = Image.open('16.tif')
i32
# <TiffImagePlugin.TiffImageFile image mode=F size=2000x1600 at 0x1098E5518>
i16
# <TiffImagePlugin.TiffImageFile image mode=I;16S size=2000x1600 at 0x1098B6DD0>
But I am having trouble working with the 16 bit image. If I want to save either as PNG, I cannot do so directly:
i32.save('foo.png')
# IOError: cannot write mode F as PNG
i16.save('foo.png')
# ValueError: unrecognized mode
If I convert the 32 bit image, I 开发者_StackOverflowcan save it:
i32.convert('L').save('foo.png')
But the same command will not work with the 16 bit image:
i16.convert('L').save('foo.png')
# ValueError: unrecognized mode
For lossless conversion from 16 bit grayscale TIFF to PNG use PythonMagick:
from PythonMagick import Image
Image('pinei_2002300_1525_modis_ch02.tif').write("foo.png")
You appear to have stumbled into a PIL bug, or a corner case that was unimplemented.
Here's a workaround:
i16.mode = 'I'
i16.point(lambda i:i*(1./256)).convert('L').save('foo.png')
Stumbled on this thread trying to save 16 bit TIFF images with PIL / numpy.
Versions: python 2.7.1 - numpy 1.6.1 - PIL 1.1.7
Here's a quick test I wrote. uint16 numpy array -> converted to string -> converted to a PIL image of type 'I;16' -> saved as a 16 bit TIFF.
Opening the image in ImageJ shows the right horizontal gradient pattern and the image type is 'Bits per pixel: 16 (unsigned)'
import Image
import numpy
data = numpy.zeros((1024,1024),numpy.uint16)
h,w = data.shape
for i in range(h):
data[i,:] = numpy.arange(w)
im = Image.fromstring('I;16',(w,h),data.tostring())
im.save('test_16bit.tif')
edit: As of 1.1.7, PIL does not support writing compressed files, but pylibtiff does (lzw compression). The test code thus becomes (tested with pylibtiff 0.3):
import Image
import numpy
from libtiff import TIFFimage
data = numpy.zeros((1024,1024),numpy.uint16)
h,w = data.shape
for i in range(w):
data[:,i] = numpy.arange(h)
tiff = TIFFimage(data, description='')
tiff.write_file('test_16bit.tif', compression='lzw')
#flush the file to disk:
del tiff
Please note: test code changed to generate a vertical gradient otherwise, no compression achieved (refer to warning: pylibtiff currently supports reading and writing images that are stored using TIFF strips).
Convert an ImageJ TIFF to a JPEG with PIL 4.1+
im = numpy.array(Image.open('my.tiff'))
image = Image.fromarray(im / numpy.amax(im) * 255)
image.save('my.jpg')
精彩评论