Python和16位PGM [英] Python and 16-bit PGM

查看:149
本文介绍了Python和16位PGM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have 16-bit PGM images that I am trying to read in Python. It seems (?) like PIL does not support this format?

import Image
im = Image.open('test.pgm')
im.show()

粗略显示图像,但是不正确.整个区域都有黑带,据报道img具有mode=L.我认为这与我对 16位TIFF文件的早期疑问有关.是不是PIL不支持16位的情况如此罕见?关于如何使用PIL或其他标准库或本地代码在Python中读取16位PGM文件的任何建议?

Shows roughly the image, but it isn't right. There are dark bands throughout and img is reported to have mode=L. I think this is related to an early question I had about 16-bit TIFF files. Is 16-bit that rare that PIL just does not support it? Any advice how I can read 16-bit PGM files in Python, using PIL or another standard library, or home-grown code?

推荐答案

以下内容仅取决于 numpy 加载图像,该图像可以是8位或16位原始PGM/PPM.我还展示了几种查看图像的不同方法.使用PIL(import Image)的用户需要首先将数据转换为8位.

The following depends only on numpy to load the image, which can be 8-bit or 16-bit raw PGM/PPM. I also show a couple different ways to view the image. The one that uses PIL (import Image) requires that the data first be converted to 8-bit.

#!/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()


使用说明

  • 我最终想出了它如何决定字节序"的方法-它实际上是将图像以大字节序(而不是本地字节序)的形式存储在内存中.这种方案可能会减慢任何不重要的图像处理速度-尽管Python的其他性能问题可能会使这种担忧变得微不足道(请参见下文).


    Usage notes

    • I eventually figured out "how it decides about endianness" -- it is actually storing the image in memory as big-endian (rather than native). This scheme might slow down any non-trivial image processing -- although other performance issues with Python may relegate this concern to a triviality (see below).

      我在此处询问了有关字节序的问题.我还遇到了一些与字节序有关的有趣混淆,因为我正在通过使用pnmdepth 65535预处理图像进行测试,这本身并不能很好地测试字节序,因为低字节和高字节最终可能是相同的(我没有不会立即注意到,因为print(array)输出十进制).我也应该应用pnmgamma来避免一些困惑.

      I asked a question related to the endianness concern here. I also ran into some interesting confusion related to endianness with this because I was testing by preprocessing the image with pnmdepth 65535 which is not good (by itself) for testing endianness since the low and high bytes might end up being the same (I didn't notice right away because print(array) outputs decimal). I should have also applied pnmgamma to save myself some confusion.

      由于Python太慢,因此numpy试图对应用某些操作的方法偷偷摸摸" (请参阅 不要编写自己的for循环 ).上面代码中的有趣之处在于,在执行示例图像处理"时,它仅部分遵循此规则,因此该行的性能与给reshape的参数有极大的依赖性.

      Because Python is so slow, numpy tries to be sneakyclever about how it applies certain operations (see broadcasting). The first rule of thumb for efficiency with numpy is let numpy handle iteration for you (or put another way don't write your own for loops). The funny thing in the code above is that it only partially follows this rule when doing the "example image processing", and therefore the performance of that line has an extreme dependency on the parameters that were given to reshape.

      下一个重要的numpy字节序大谜:为什么newbyteorder()似乎

      The next big numpy endianness mystery: Why does newbyteorder() seem to return an array, when it's documented to return a dtype. This is relevant if you want to convert to native endian with dst.pixels=dst.pixels.byteswap(True).newbyteorder().

      移植到Python 3的提示:具有ASCII文本标头的二进制输入,可从stdin中读取

      Hints on porting to Python 3: binary input with an ASCII text header, read from stdin

      这篇关于Python和16位PGM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆