Python与16位PGM

Python与16位PGM,python,python-imaging-library,16-bit,pgm,Python,Python Imaging Library,16 Bit,Pgm,我有16位PGM图像,我正在尝试用Python阅读。似乎(?)PIL不支持这种格式 import Image im = Image.open('test.pgm') im.show() 大致显示了图像,但不正确。整个过程中都有暗带,据报告img有mode=L。我想这与我之前的一个问题有关。16位是不是很少见,PIL就是不支持它?有什么建议可以让我使用PIL或其他标准库,或者自己编写的代码,在Python中读取16位PGM文件吗?您需要“L;16”模式;但是,在加载PGM时,PIL的模式似乎是硬

我有16位PGM图像,我正在尝试用Python阅读。似乎(?)PIL不支持这种格式

import Image
im = Image.open('test.pgm')
im.show()
大致显示了图像,但不正确。整个过程中都有暗带,据报告img有
mode=L
。我想这与我之前的一个问题有关。16位是不是很少见,PIL就是不支持它?有什么建议可以让我使用PIL或其他标准库,或者自己编写的代码,在Python中读取16位PGM文件吗?

您需要
“L;16”
模式;但是,在加载PGM时,PIL的模式似乎是硬编码到File.c中的
“L”
。如果你想阅读16位PGM,你就必须这样做

但是,16位图像支持似乎仍然很脆弱:

>>> im = Image.fromstring('I;16', (16, 16), '\xCA\xFE' * 256, 'raw', 'I;16') 
>>> im.getcolors()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.6/dist-packages/PIL/Image.py", line 866, in getcolors
    return self.im.getcolors(maxcolors)
ValueError: image has wrong mode
im=Image.fromstring('I;16',(16,16),'\xCA\xFE'*256,'raw','I;16') >>>im.getcolors() 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 文件“/usr/lib/python2.6/dist packages/PIL/Image.py”,第866行,格式为GetColor 返回self.im.getcolors(maxcolors) ValueError:图像的模式错误 我认为PIL能够读取16位的图像,但实际上存储和操作它们仍然是实验性的

>>> im = Image.fromstring('L', (16, 16), '\xCA\xFE' * 256, 'raw', 'L;16') 
>>> im
<Image.Image image mode=L size=16x16 at 0x27B4440>
>>> im.getcolors()
[(256, 254)]
im=Image.fromstring('L',(16,16),'\xCA\xFE'*256,'raw','L;16') >>>即时通讯 >>>im.getcolors() [(256, 254)] 请参阅,它只是将
0xCAFE
值解释为
0xFE
,这并不完全正确。

这里有一个基于的通用/读取器和中的一个未记录函数

def read_pnm(文件名,endian='>'):
fd=打开(文件名为'rb')
格式、宽度、高度、样本,maxval=png.read_pnm_头(fd)
pixels=numpy.fromfile(如果maxval<256 else endian+'u2',则fd,dtype='u1')
返回像素。重塑(高度、宽度、样本)

当然,编写此图像格式通常不需要库的帮助…

以下内容仅取决于加载图像,图像可以是8位或16位原始PGM/PPM。我还展示了查看图像的几种不同方式。使用PIL(
导入图像
)的程序要求首先将数据转换为8位

#!/usr/bin/python2 -u

from __future__ import print_function
import sys, numpy

def read_pnm_from_stream( fd ):
   pnm = type('pnm',(object,),{}) ## create an empty container
   pnm.header = fd.readline()
   pnm.magic = pnm.header.split()[0]
   pnm.maxsample = 1 if ( pnm.magic == 'P4' ) else 0
   while ( len(pnm.header.split()) < 3+(1,0)[pnm.maxsample] ): s = fd.readline() ; pnm.header += s if ( len(s) and s[0] != '#' ) else ''
   pnm.width, pnm.height = [int(item) for item in pnm.header.split()[1:3]]
   pnm.samples = 3 if ( pnm.magic == 'P6' ) else 1
   if ( pnm.maxsample == 0 ): pnm.maxsample = int(pnm.header.split()[3])
   pnm.pixels = numpy.fromfile( fd, count=pnm.width*pnm.height*pnm.samples, dtype='u1' if pnm.maxsample < 256 else '>u2' )
   pnm.pixels = pnm.pixels.reshape(pnm.height,pnm.width) if pnm.samples==1 else pnm.pixels.reshape(pnm.height,pnm.width,pnm.samples)
   return pnm

if __name__ == '__main__':

## read image
 # src = read_pnm_from_stream( open(filename) )
   src = read_pnm_from_stream( sys.stdin )
 # print("src.header="+src.header.strip(), file=sys.stderr )
 # print("src.pixels="+repr(src.pixels), file=sys.stderr )

## write image
   dst=src
   dst.pixels = numpy.array([ dst.maxsample-i for i in src.pixels ],dtype=dst.pixels.dtype) ## example image processing
 # print("dst shape: "+str(dst.pixels.shape), file=sys.stderr )
   sys.stdout.write(("P5" if dst.samples==1 else "P6")+"\n"+str(dst.width)+" "+str(dst.height)+"\n"+str(dst.maxsample)+"\n");
   dst.pixels.tofile( sys.stdout ) ## seems to work, I'm not sure how it decides about endianness

## view using Image
   import Image
   viewable = dst.pixels if dst.pixels.dtype == numpy.dtype('u1') else numpy.array([ x>>8 for x in dst.pixels],dtype='u1')
   Image.fromarray(viewable).show()

## view using scipy
   import scipy.misc
   scipy.misc.toimage(dst.pixels).show()
#/usr/bin/python2-u
来自未来导入打印功能
导入系统,numpy
def从_流(fd)读取_pnm_:
pnm=type('pnm',(object,),{})##创建一个空容器
pnm.header=fd.readline()
pnm.magic=pnm.header.split()[0]
如果(pnm.magic=='P4')其他值为0,则pnm.maxsample=1
而(len(pnm.header.split())<3+(1,0)[pnm.maxsample]):s=fd.readline();pnm.header+=s if(len(s)和s[0]!='#')else''
pnm.width,pnm.height=[pnm.header.split()[1:3]]中项目的int(项目)
pnm.samples=3如果(pnm.magic=='P6')其他1
if(pnm.maxsample==0):pnm.maxsample=int(pnm.header.split()[3])
pnm.pixels=numpy.fromfile(fd,count=pnm.width*pnm.height*pnm.samples,如果pnm.maxsample<256 else'>u2',则dtype='u1')
如果pnm.samples==1,则pnm.pixels=pnm.pixels.reformate(pnm.height,pnm.width),否则pnm.pixels.reformate(pnm.height,pnm.width,pnm.samples)
返回pnm
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
##读取图像
#src=从\u流读取\u pnm\u(打开(文件名))
src=从\u流(sys.stdin)读取\u pnm\u
#打印(“src.header=“+src.header.strip(),file=sys.stderr”)
#打印(“src.pixels=“+repr(src.pixels),file=sys.stderr)
##书写图像
dst=src
dst.pixels=numpy.array([dst.maxsample-i代表src.pixels中的i],dtype=dst.pixels.dtype)##图像处理示例
#打印(“dst形状:”+str(dst.pixels.shape),file=sys.stderr)
sys.stdout.write((“P5”如果dst.samples==1,则为“P6”)+“\n”+str(dst.width)+“+str(dst.height)+”“\n”+str(dst.maxsample)+”\n”);
dst.pixels.tofile(sys.stdout)###似乎有效,我不确定它如何决定endianness
##使用图像查看
导入图像
如果dst.pixels.dtype==numpy.dtype('u1'),则viewable=dst.pixels,否则为numpy.array([x>>8,表示x在dst.pixels中),dtype='u1')
Image.fromarray(可视).show()
##使用scipy查看
导入scipy.misc
scipy.misc.toimage(dst.pixels.show())

使用说明
  • 我最终弄明白了“它是如何决定endian的”——它实际上是将图像作为big endian(而不是本机)存储在内存中。这个方案可能会减慢任何非平凡的图像处理速度——尽管Python的其他性能问题可能会使这个问题变得微不足道(见下文)

  • 我问了一个关于endianness的问题。我还遇到了一些与endianness相关的有趣的混淆,因为我是通过使用
    pnmdepth 65535
    对图像进行预处理来进行测试的,这对于测试endianness来说(本身)是不好的,因为低字节和高字节可能最终是相同的(我没有立即注意到,因为
    打印(数组)
    输出十进制)。我也应该应用
    pnmgamma
    来避免一些困惑

  • 由于Python速度非常慢,
    numpy
    试图对它如何应用某些操作保持谨慎(请参阅)。使用
    numpy
    提高效率的第一条经验法则是让numpy为您处理迭代(或者换一种方式)。上面代码中有趣的一点是,在执行“示例图像处理”时,它仅部分遵循此规则,因此该行的性能与
    重塑
    的参数有极大的依赖性

  • 下一个大的
    numpy
    endianness之谜:当返回
    dtype
    时,为什么
    newbyteorder()
    看起来会这样。如果要使用
    dst.pixels=dst.pixels.byteswap(True).newbyteorder()
    将其转换为本机endian,则这与此相关

  • 关于移植到Python 3的提示:


我很乐意阅读它们。如果我需要写,我会使用PNG。我也可以将它们作为numpy中的数据处理,而不是作为PIL中的图像处理。你的帖子很有帮助,但是你能详细说明我如何正确读取数据吗?你是说写一个解码器吗
#!/usr/bin/python2 -u

from __future__ import print_function
import sys, numpy

def read_pnm_from_stream( fd ):
   pnm = type('pnm',(object,),{}) ## create an empty container
   pnm.header = fd.readline()
   pnm.magic = pnm.header.split()[0]
   pnm.maxsample = 1 if ( pnm.magic == 'P4' ) else 0
   while ( len(pnm.header.split()) < 3+(1,0)[pnm.maxsample] ): s = fd.readline() ; pnm.header += s if ( len(s) and s[0] != '#' ) else ''
   pnm.width, pnm.height = [int(item) for item in pnm.header.split()[1:3]]
   pnm.samples = 3 if ( pnm.magic == 'P6' ) else 1
   if ( pnm.maxsample == 0 ): pnm.maxsample = int(pnm.header.split()[3])
   pnm.pixels = numpy.fromfile( fd, count=pnm.width*pnm.height*pnm.samples, dtype='u1' if pnm.maxsample < 256 else '>u2' )
   pnm.pixels = pnm.pixels.reshape(pnm.height,pnm.width) if pnm.samples==1 else pnm.pixels.reshape(pnm.height,pnm.width,pnm.samples)
   return pnm

if __name__ == '__main__':

## read image
 # src = read_pnm_from_stream( open(filename) )
   src = read_pnm_from_stream( sys.stdin )
 # print("src.header="+src.header.strip(), file=sys.stderr )
 # print("src.pixels="+repr(src.pixels), file=sys.stderr )

## write image
   dst=src
   dst.pixels = numpy.array([ dst.maxsample-i for i in src.pixels ],dtype=dst.pixels.dtype) ## example image processing
 # print("dst shape: "+str(dst.pixels.shape), file=sys.stderr )
   sys.stdout.write(("P5" if dst.samples==1 else "P6")+"\n"+str(dst.width)+" "+str(dst.height)+"\n"+str(dst.maxsample)+"\n");
   dst.pixels.tofile( sys.stdout ) ## seems to work, I'm not sure how it decides about endianness

## view using Image
   import Image
   viewable = dst.pixels if dst.pixels.dtype == numpy.dtype('u1') else numpy.array([ x>>8 for x in dst.pixels],dtype='u1')
   Image.fromarray(viewable).show()

## view using scipy
   import scipy.misc
   scipy.misc.toimage(dst.pixels).show()