2011-09-09 10 views
5

मेरे पास 16-बिट पीजीएम छवियां हैं जिन्हें मैं पायथन में पढ़ने की कोशिश कर रहा हूं। ऐसा लगता है (?) जैसे पीआईएल इस प्रारूप का समर्थन नहीं करता है?पायथन और 16-बिट पीजीएम

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

मोटे तौर पर छवि दिखाता है, लेकिन यह सही नहीं है। पूरे अंधेरे बैंड हैं और आईएमजी mode=L होने की सूचना दी गई है। मुझे लगता है कि यह शुरुआती प्रश्न से संबंधित है जिसमें मेरे पास 16-bit TIFF files था। 16-बिट इतना दुर्लभ है कि पीआईएल सिर्फ इसका समर्थन नहीं करता है? कोई सलाह है कि मैं पीआईएल या अन्य मानक पुस्तकालय, या घर से उगाए गए कोड का उपयोग कर पाइथन में 16-बिट पीजीएम फ़ाइलों को कैसे पढ़ सकता हूं?

उत्तर

1

निम्नलिखित छवि को लोड करने केवल numpy पर निर्भर करता है, जो 8 बिट है या कर सकते हैं 16-बिट कच्चे पीजीएम/पीपीएम। मैं छवि को देखने के लिए कुछ अलग तरीके भी दिखाता हूं। वह जो पीआईएल (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() 

प्रयोग नोटों

  • मैं अंत में पता लगा "यह कैसे endianness के बारे में फैसला करता है" - यह वास्तव में स्मृति के रूप में बड़े endian (बल्कि देशी की तुलना में) में छवि संग्रहीत किया जाता है। यह योजना किसी भी गैर-तुच्छ छवि प्रसंस्करण को धीमा कर सकती है - हालांकि पाइथन के साथ अन्य प्रदर्शन समस्याएं इस चिंता को एक तुच्छता (नीचे देखें) में ला सकती हैं।

  • मैंने एंडियननेस चिंता here से संबंधित एक प्रश्न पूछा। मैं इसके साथ अंतहीनता से संबंधित कुछ रोचक भ्रम में भी भाग गया क्योंकि मैं pnmdepth 65535 के साथ छवि को प्रीप्रोसेसिंग करके परीक्षण कर रहा था जो कम और उच्च बाइट्स के समान होने के कारण (अंत में) अंतहीनता का परीक्षण करने के लिए अच्छा नहीं है (मैंने नहीं किया तुरंत ध्यान दें क्योंकि print(array) दशमलव आउटपुट करता है)। मुझे कुछ भ्रम बचाने के लिए pnmgamma भी लागू करना चाहिए था।

  • क्योंकि अजगर इतनी धीमी गति से है, numpy डरपोक के बारे में यह कैसे निश्चित संचालनों (broadcasting देखें) लागू होता है चतुर होने की कोशिश करता है। numpy के साथ दक्षता के लिए अंगूठे का पहला नियम आपके लिए (या कोई अन्य तरीका don't write your own for loops) रखता है। उपर्युक्त कोड में मजाकिया बात यह है कि "उदाहरण छवि प्रसंस्करण" करते समय यह केवल आंशिक रूप से इस नियम का पालन करता है, और इसलिए उस रेखा के प्रदर्शन में reshape को दिए गए पैरामीटर पर अत्यधिक निर्भरता है।

  • अगली बड़ी numpy endianness रहस्य: क्यों newbyteorder()return an array लगते है, जब यह एक dtype वापस जाने के लिए documented है। यह प्रासंगिक है यदि आप देशी एंडियन में dst.pixels=dst.pixels.byteswap(True).newbyteorder() के साथ कनवर्ट करना चाहते हैं। अजगर से 3 पोर्टिंग पर

  • संकेत: binary input with an ASCII text header, read from stdin

+0

प्रतीत होता है कि छोटे-छोटे पायथन प्रोग्राम लिखने का प्रयास क्यों हमेशा स्टैक ओवरफ़्लो के माध्यम से ओडिसी में होता है? – nobar

+0

चीजें जो मुझे पाइथन के बारे में पागल बनाती हैं उनमें से एक उथली प्रतियां है, जैसे ऊपर 'dst = src'। कभी-कभी मुझे लगता है कि एक सी ++ प्रोग्रामर को समझने के लिए पाइथन बहुत मुश्किल है। – nobar

+0

... मुझे सबसे कम वोट वाले उत्तरों में से कुछ मिला [यहां] (http://stackoverflow.com/questions/9541025/how-to-copy-a-python-class) सबसे उपयोगी होने के लिए। विशेष रूप से, ऐसा लगता है कि मैं 'dst = src()' कर कर अपनी समस्या को हल कर सकता हूं। – nobar

4

आपको "L;16" का एक मोड चाहिए; हालांकि ऐसा लगता है कि पीआईएल में "L" का एक तरीका है जो पीजीएम लोड करते समय File.c में हार्डकोड किया गया है। यदि आप 16-बिट पीजीएम पढ़ने में सक्षम होना चाहते हैं तो आपको 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 

मुझे लगता है कि जनहित याचिका 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

मैं सिर्फ उन्हें पढ़ने के लिए खुश हूँ। अगर मुझे लिखने की ज़रूरत है तो मैं पीएनजी का उपयोग करूंगा। मैं उन्हें पीआईएल में एक छवि के बजाय numpy में डेटा के रूप में जोड़कर ठीक हूँ। आपकी पोस्ट सहायक रही है, लेकिन क्या आप विस्तार कर सकते हैं कि मैं डेटा में सही ढंग से कैसे पढ़ सकता हूं? – mankoff

+0

क्या आपका मतलब है पीआईएल के लिए एक डिकोडर लिखना, या पीजीएम की व्याख्या कैसे करें? –

+0

आपका इटालिकाइज्ड '' 'रीडिंग' '' ने मुझे लगा कि शायद यह काम करने के लिए कुछ चाल है? मैं यहां काम को अनुकूलित करने की कोशिश कर रहा हूं (http://stackoverflow.com/questions/7247371/python-and-16-bit-tiff) लेकिन बिट्स खोने के बिना। यदि एक कस्टम डिकोडर की आवश्यकता है तो मैं इसे पीआईएल ट्यूटोरियल के आधार पर लिखूंगा। पीजीएम प्रारूप बहुत बुनियादी लगता है, तो शायद मुझे इसे सीधे numpy में पढ़ना चाहिए ... – mankoff

1

यहाँ एक सामान्य PNM/PAM पाठक NumPy पर आधारित है और 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

'पीएएम' समर्थन के संबंध में, यहां इस्तेमाल किया गया 'read_pnm_header() 'फ़ंक्शन' TUPLTYPE' वापस नहीं करता है, लेकिन यह 'DEPTH' (जिसे मैंने' नमूने 'कहा जाता है) के लिए सही मान वापस कर दिया है। – nobar

+0

फ़ाइल के बजाए stdio का उपयोग करने पर महत्वपूर्ण नोट्स के लिए [यह प्रश्न] देखें (http://stackoverflow.com/questions/2850893/reading-binary-data-from-stdin)। – nobar

संबंधित मुद्दे