2011-09-09 24 views
5

Python'da okumaya çalıştığım 16 bit PGM resimlerim var. PIL gibi bu formatı desteklemiyor gibi görünüyor?Python ve 16 bit PGM

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

Görüntüyü kabaca gösterir, ancak doğru değil. Boyunca karanlık bantlar vardır ve img'in mode=L olduğu bildirilmiştir. Ben bu konuda 16-bit TIFF files hakkında bir erken soru ile ilgili olduğunu düşünüyorum. 16-bit o PIL sadece bunu desteklemiyor nadir mi? Python'da PIL veya başka bir standart kütüphane veya evde yetiştirilen kodu kullanarak 16 bit PGM dosyalarını nasıl okuyabileceğime dair herhangi bir tavsiye var mı?

cevap

1

şu resim yüklemek için tek numpy bağlıdır hangi 8 bitlik ya da olabilir 16 bit ham PGM/PPM. Ayrıca görüntüyü görmenin birkaç farklı yolunu da gösteriyorum. PIL (import Image) kullananı, verilerin önce 8-bit'e dönüştürülmesini gerektirir.

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

Kullanım notları

  • Sonunda "O endian hakkında nasıl karar verir" anladım - aslında (ziyade yerli yerine) bellek gibi büyük-endian görüntüyü depoluyor. Bu şema herhangi bir önemsiz olmayan görüntü işlemeyi yavaşlatabilir - Python ile ilgili diğer performans sorunları bu kaygıyı önemsizliğe indirebilir (aşağıya bakınız).

  • Endianness endişesi here ile ilgili bir soru sordum. Ben de endonite ile ilgili bazı ilginç karışıklık içine koştum çünkü ben düşük ve yüksek baytlar aynı olsaydı ben bitmiş olabilir çünkü endianness test için iyi değil (kendisi) iyi değil pnmdepth 65535 ile ön işleme ile test edildi hemen dikkat edin, çünkü print(array) ondalık basılır). Kendimi biraz kafa karışıklığına uğratmak için pnmgamma'u da kullanmalıydım.Python çok yavaş olduğu için

  • , numpy belli işlemleri (broadcasting bakınız) uygulanması hakkında sinsi zeki olmaya çalışır. numpy ile verimlilik için baştaki ilk kural sizin için bir tutam tutamaya izin verir (ya da başka bir yolla don't write your own for loops). Yukarıdaki koddaki komik şey, "örnek görüntü işleme" yapılırken bu kuralı yalnızca kısmen takip etmesidir ve bu nedenle bu çizginin performansı reshape'a verilen parametrelere aşırı bağımlıdır.

  • sonraki büyük numpy endian gizem: Bir dtype dönmek için documented geldiğinde, newbyteorder()return an array görünüyor yapar Neden. Bu, dst.pixels=dst.pixels.byteswap(True).newbyteorder() ile yerel endian'a dönüştürmek istiyorsanız uygundur. Python 3'e taşıma üzerine

  • İpuçları: binary input with an ASCII text header, read from stdin

+0

Görünüşte önemsiz görünen Python programlarını yazmaya çalışmak neden her zaman Stack Overflow üzerinden bir odyssey ile sonuçlanıyor gibi görünüyor? – nobar

+0

Python hakkında beni çıldırtan şeylerden biri, yukarıdaki dst = src gibi sığ kopyalardır. Bazen Python'un bir C++ programcısı için anlaması çok zor olduğunu düşünüyorum. – nobar

+0

... En düşük oyu alan cevaplardan [burada] (http://stackoverflow.com/questions/9541025/how-to-copy-a-python-class) en faydalı olanlarını buldum. Özellikle, yukarıdaki sorunu dst = src() 'yaparak çözebilirim. – nobar

4

"L;16"; ancak PIL, bir PGM yüklerken File.c'ye kodlanmış "L" moduna sahiptir. Bir 16 bit PGM okuyabilmeniz için write your own decoder olmalıdır.

Ancak 16 bit görüntü desteği hala pul pul görünüyor:

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

Ben PIL 16 bit ile görüntüleri okuma, ama aslında saklamak ve onları hala deneysel olan manipüle edebilen olduğunu düşünüyorum.

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

bakın, sadece tam olarak doğru değil, hangi 0xFE olarak 0xCAFE değeri yorumlanır.

+0

Sadece onları okumak için mutluyum. Yazmam gerekirse PNG kullanacağım. Bunları PIL'de görüntü olarak değil, numpy cinsinden veri olarak manipüle etmede de iyiyim. Gönderiniz yardımcı oldu, ancak verilerde doğru bir şekilde nasıl okuyabileceğimi açabiliyor musunuz? – mankoff

+0

PIL için bir kod çözücü yazmak mı yoksa PGM'yi nasıl yorumlamak istiyorsunuz? –

+0

Italicized '' 'reading' '' bana bunun gibi çalışmasını sağlamak için bir numara olduğunu düşünmemi sağladı mı? Buradaki çalışmayı uyarlamaya çalışıyorum (http://stackoverflow.com/questions/7247371/python-and-16-bit-tiff) ancak bitleri kaybetmeden. Eğer özel bir kod çözücüye ihtiyaç varsa, bunu PIL eğitimine göre yazacağım. PGM formatı oldukça basit görünüyor, bu yüzden belki de sadece numpy içine okumalıyım ... – mankoff

1

İşte NumPy dayalı bir jenerik PNM/PAM okuyucu ve PyPNG bir belgesiz fonksiyon. Bu resim biçimi genellikle kütüphanenin yardım gerektirmez

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

yazı ...

+0

[Bu konuyla ilgili sorudan] bazı fikirler aldım (http://stackoverflow.com/questions/7368739/numpy-and-16-bit-pgm). – nobar

+0

'PAM' desteği ile ilgili olarak, burada kullanılan "read_pnm_header()" işlevi "TUPLTYPE" değerini döndürmez, ancak "DEPTH" için ("samples' denir") doğru değerini döndürür. – nobar

+0

Bir dosya yerine stdio kullanımıyla ilgili önemli notlar için [bu soru] bölümüne bakın (http://stackoverflow.com/questions/2850893/reading-binary-data-from-stdin). – nobar

İlgili konular