Python 与 16 位 TIFF

16 投票
4 回答
32554 浏览
提问于 2025-04-17 00:44

我想知道如何在Python中转换并保存一个16位单通道的TIF文件。

我可以顺利加载16位和32位的图像,并且看到32位的图像模式是F,而16位的图像模式是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>

但是我在处理16位图像时遇到了麻烦。如果我想把它保存为PNG格式,直接保存是行不通的:

i32.save('foo.png')
# IOError: cannot write mode F as PNG
i16.save('foo.png')
# ValueError: unrecognized mode

如果我把32位的图像转换一下,就可以保存了:

i32.convert('L').save('foo.png')

但是同样的命令在16位图像上就不管用了:

i16.convert('L').save('foo.png')
# ValueError: unrecognized mode

4 个回答

8

我在找方法用PIL和numpy保存16位的TIFF图片时,偶然发现了这个讨论。

使用的版本是:python 2.7.1 - numpy 1.6.1 - PIL 1.1.7

我写了一个简单的测试。首先是一个uint16的numpy数组,然后把它转换成字符串,再转换成PIL的'I;16'类型的图片,最后保存为16位的TIFF格式。

在ImageJ中打开这个图片,能看到正确的水平渐变效果,图片类型显示为'每像素位数:16(无符号)'

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')

补充: 从1.1.7版本开始,PIL不支持写入压缩文件,但pylibtiff支持(使用lzw压缩)。所以测试代码变成了(在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

请注意:测试代码改成生成垂直渐变,否则无法实现压缩(参考警告:pylibtiff目前支持读取和写入使用TIFF条带存储的图片)。

8

看起来你遇到了PIL(Python图像库)中的一个小问题,或者是一个没有实现的特殊情况。

这里有一个解决办法:

i16.mode = 'I'
i16.point(lambda i:i*(1./256)).convert('L').save('foo.png')
9

如果你想把16位灰度的TIFF图片无损地转换成PNG格式,可以使用PythonMagick这个工具:

from PythonMagick import Image
Image('pinei_2002300_1525_modis_ch02.tif').write("foo.png")

撰写回答