2011-09-09 33 views
5

私はPythonで読み込もうとしている16ビットのPGMイメージを持っています。 PILのようなこの形式をサポートしていないようですか?Pythonと16ビットPGM

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

画像はおおよそ次のように表示されますが、正しくはありません。全体にダークバンドがあり、imgはmode=Lと報告されています。私はこれが最初の質問に関連していると思います。16-bit TIFF files。まれにPILがサポートしていないのは16ビットですか?どのように私はPythonで他の標準ライブラリ、または自家製コードを使用して、16ビットのPGMファイルを読むことができますアドバイス?

答えて

1

以下は、8ビットの可能イメージをロードするためにnumpyにのみ依存しますか16ビットの未処理PGM/PPM。私はまた、画像を見るためのいくつかの異なる方法を示しています。 PIL(import Image)を使用するものでは、データを最初に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() 

使用上の注意

  • 私は最終的に「それはエンディアンについてはどのように決定するか」を考え出し - それは実際に(むしろネイティブより)ビッグエンディアンとしてメモリに画像を記憶しています。このスキームは、自明ではない画像処理を遅くする可能性がありますが、Pythonの他のパフォーマンスの問題がこの懸念をトリビュアリティーに陥らせる可能性があります(下記参照)。

  • エンディアンに関する懸念に関する質問hereを尋ねました。私はまた、endiannessをテストするためには、それ自身では良くないpnmdepth 65535の画像を前処理してテストしていたので、endiannessに関する面白い混乱に遭遇しました。 print(array)は10進数を出力するため、すぐに通知してください)。私も混乱を避けるためにpnmgammaを適用していたはずです。

  • Pythonは(broadcastingを参照)、それは特定の操作を適用する方法については賢い卑劣なになろうとnumpy、とても遅いので。 numpyの効率のための最初のルールは、です。numpyはあなたのために反復を処理します(別の方法ではdon't write your own for loopsを入れてください)。上のコードの面白いことは、「画像処理の例」を実行するときにこの規則に部分的に従うだけなので、その行のパフォーマンスはreshapeに与えられたパラメータに極端に依存するということです。

  • 次の大きなnumpyエンディアンの謎:なぜnewbyteorder()は、それがdtypeを返すためにdocumentedだとき、return an arrayに思えるん。これは、dst.pixels=dst.pixels.byteswap(True).newbyteorder()でネイティブエンディアンに変換する場合に関係します。 Pythonの3への移植に

  • ヒント:binary input with an ASCII text header, read from stdin

+0

どうやら些細なPythonプログラムを書こうとすると、スタックオーバーフローによって常に奇妙な結果になるようです。 – nobar

+0

Pythonについて私を夢中にさせるものの1つは、上の 'dst = src'のような浅いコピーです。時には、私は、PythonがC++プログラマーにとって理解しにくいと思うこともあります。 – nobar

+0

...私は、最も有益な投票回答(ここではhttp://stackoverflow.com/questions/9541025/how-to-copy-a-python-class)を見つけました。特に、上記の問題を 'dst = src()'を実行することで解決できるように見えます。 – nobar

4

"L;16"のモードが必要です。しかし、PILは、PGMをロードするときにFile.cにハードコードされた"L"のモードを持っているようです。 16ビットPGMを読み込めるようにするには、write your own decoderが必要です。

ただし、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 

私は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)] 

を参照してください、それだけで正確に正しいされていない、0xFEとして0xCAFE値を解釈します。

+0

私はちょうどそれらを読むことがうれしいです。私が書く必要があるなら、私はPNGを使用します。私はPILの画像ではなくnumpyでデータとして扱うこともOKです。投稿は役に立ちましたが、データを正しく読み込む方法を拡張できますか? – mankoff

+0

PIL用のデコーダの作成、またはPGMの解釈方法を教えてください。 –

+0

あなたのイタリック体で読むことは、おそらくそれをそのまま動作させるためのトリックがあると思いましたか?私はここで回避策(http://stackoverflow.com/questions/7247371/python-and-16-bit-tiff)を修正しようとしていますが、ビットを失うことはありません。カスタムデコーダが必要な場合は、PILチュートリアルに基づいて記述します。 PGM形式はかなり基本的なので、おそらく私はちょうどnumpyにそれを読むべきです... – mankoff

1

ここには、NumPyに基づくPNM/PAMリーダと、文書化されていない関数PyPNGがあります。この画像フォーマットは、一般的に、ライブラリの支援を必要としませんを書いもちろん

def read_pnm(filename, endian='>'): 
    fd = open(filename,'rb') 
    format, width, height, samples, maxval = png.read_pnm_header(fd) 
    pixels = numpy.fromfile(fd, dtype='u1' if maxval < 256 else endian+'u2') 
    return pixels.reshape(height,width,samples) 

...

+0

[この関連する質問](http://stackoverflow.com/questions/7368739/numpy-and-16-bit-pgm)からいくつかのアイデアを借りました。 – nobar

+0

'PAM'サポートに関して、ここで使用される 'read_pnm_header()'関数は 'TUPLTYPE'を返しませんが、' DEPTH'(これは 'samples'と呼ばれます)の正しい値を返します。 – nobar

+0

ファイルの代わりにstdioを使用する際の重要な注意事項については、[この質問](http://stackoverflow.com/questions/2850893/reading-binary-data-from-stdin)を参照してください。 – nobar

関連する問題