Python PIL与未压缩的16位TIFF图像斗争

问题描述:

我的系统是Mac OS X v10.8.2。我有几个2560x500未压缩的16位TIFF图像(灰度,无符号16位整数)。我第一次尝试使用PIL(通过自制软件,版本1.7.8安装)来加载它们:Python PIL与未压缩的16位TIFF图像斗争

from PIL import Image 
import numpy as np 

filename = 'Rocks_2ptCal_750KHz_20ms_1ma_120KV_2013-03-06_20-02-12.tif' 
img = Image.open(filename) 

# >>> img 
# <PIL.TiffImagePlugin.TiffImageFile image mode=I;16B size=2560x500 at 0x10A383C68> 

img.show() 

# almost all pixels displayed as white. Not correct. 
# MatLab, EZ-draw, even Mac Preview show correct images in grayscale. 

imgdata = list(img.getdata()) 

# most values negative: 
# >>> imgdata[0:10] 
# [-26588, -24079, -27822, -26045, -27245, -25368, -26139, -28454, -30675, -28455] 

imgarray = np.asarray(imgdata, dtype=np.uint16) 

# values now correct 
# >>> imgarray 
# array([38948, 41457, 37714, ..., 61922, 59565, 60035], dtype=uint16) 

负值是关闭65,536 ......也许不是巧合。

如果我假装改变像素,并通过PIL恢复到TIFF图像(仅通过把数组回为图像):

newimg = Image.fromarray(imgarray) 

我得到的错误:

File "/usr/local/lib/python2.7/site-packages/PIL/Image.py", line 1884, in fromarray 
    raise TypeError("Cannot handle this data type") 
TypeError: Cannot handle this data type 

我可以在PIL文档中找不到Image.fromarray()。我试过通过Image.fromstring()加载,但我不明白PIL文档,并且没有太多例子。

如上面代码所示,PIL似乎“检测”数据为I;16B。从我可以从PIL文档告诉,模式I是:

*I* (32-bit signed integer pixels) 

显然,这是不正确的。

我在SX上发现很多帖子提示PIL不支持16位图像。我发现了使用pylibtiff的建议,但我相信这只是Windows?

我正在寻找一种“轻量级”的方式来处理Python中的这些TIFF图像。我很惊讶这是困难的,这导致我相信这个问题对其他人来说显而易见。

+0

您可以发布示例文件的某个地方吗? – nneonneo 2013-03-08 00:36:30

+1

PIL与许多事情斗争,即使像隔行PNG一样简单。我倾向于怀疑它不能正确支持16位图像。 – duskwuff 2013-03-08 00:53:59

+0

@nneonneo不幸的是,我正在使用的文件中的数据是专有的,我不确定如何给这个例子的TIFF失败。我知道这样做很难排除故障,但我希望有人知道该怎么做......我试图尽可能全面地编写脚本 – ph0t0n 2013-03-08 00:59:54

事实证明,在Matplotlib 行代码处理16位未压缩的TIFF图像:

import matplotlib.pyplot as plt 
img = plt.imread(filename) 

# >>> img 
# array([[38948, 41457, 37714, ..., 61511, 61785, 61824], 
#  [39704, 38083, 36690, ..., 61419, 60086, 61910], 
#  [41449, 39169, 38178, ..., 60192, 60969, 63538], 
#  ..., 
#  [37963, 39531, 40339, ..., 62351, 62646, 61793], 
#  [37462, 37409, 38370, ..., 61125, 62497, 59770], 
#  [39753, 36905, 38778, ..., 61922, 59565, 60035]], dtype=uint16) 

的Et瞧。我想这不符合我的要求,因为Matplotlib对我来说是一个重量级的模块,但将图像转换为Numpy数组非常简单。我希望这可以帮助别人快速找到解决方案,因为这对我来说并不明显。

+0

我也在使用16位无压缩的TIFF图像。我必须有一个稍微不同的Matplotlib版本,或者稍微不同的TIFF图片,因为这段代码对我来说不起作用。Matplotlib返回一个尺寸为(1024,1024,4)而不是(1024,1024)的数组,并且调用max(img.ravel())所指示的图像最大值被错误地缩小为255。对于它的价值,我诉诸于在Matlab中加载我的图像,并将它们保存为mat文件,这些文件可以通过scipy可靠地加载。 – 2013-07-06 05:15:15

+0

@Mike Roberts,数组(4)的最后一个维可能包含像素的每个组件。 RGB(A)像素的每个分量通常都是8位长,这就是为什么最大值为255,这意味着它比获得简单的1024x1024数组更好。您仍然可以通过对每个二进制元素进行“或”运算将这4个元件转换为一个32位长的元件,例如。 red |绿色 2013-08-12 06:33:13

+1

@SteveK嗨SteveK,感谢您的建议。我不同意你声称在返回的数组上执行位操作“甚至比获得简单的1024x1024数组更好”。 OP询问大约16位灰度TIFF图像,所以唯一合适的返回类型是uint16的一个1024x1024,至少在我看来。而且,作为这个bit-twiddling接口的客户端,我该如何知道alpha包含高位字节,而红色包含低位字节?并不总是遵守这种约定(例如,彩色图像数据有时被存储为BGRA)。 – 2013-08-22 06:40:29

尝试Pillow,“友好”PIL叉。他们最近增加了对16位和32位图像的更好支持,包括在numpy阵列接口中。此代码将与最新的枕头一起使用:

from PIL import Image 
import numpy as np 

img = Image.open('data.tif') 
data = np.array(img)