2014-11-07 13 views
7

कोई सुझाव दे सकता है कि BufferedImage जावा में किसी छवि को संसाधित करने का सबसे अच्छा विकल्प है। हालांकि यह सुविधाजनक है, जब बड़ी छवियों को पढ़ने यह अक्सर ऊपर समाप्त होता है:स्ट्रीम से छवि को कैसे पढ़ा जाए?

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 

बढ़ाने से वीएम आकार एक समाधान नहीं है, क्योंकि कुछ इनपुट फ़ाइलें वास्तव में मेरे मामले में बहुत बड़ा कर रहे हैं।

तो मैं स्ट्रीम से एक छवि को प्रगतिशील तरीके से कैसे पढ़ा जा सकता हूं, इस तरह की तलाश कर रहा हूं।

मुझे संदेह है कि ImageIO.createImageInputStream()ImageIO से बिल फिट हो सकता है, लेकिन मुझे यकीन नहीं है कि chunks को क्रमशः पढ़ने के लिए इसका उपयोग कैसे किया जाए। इसके अलावा, कक्षाएं PNGMetadata & PNGImageReader जेडीके के rt.jar पर उपलब्ध हैं जो उपयोगी प्रतीत होती हैं, लेकिन मुझे उनके उपयोग के सरल उदाहरण नहीं मिला।

क्या यह जाने का तरीका है, या बेहतर विकल्प हैं?

+0

अगर आप बंद करने के लिए वोट डालें या वोट डालें तो कृपया एक टिप्पणी छोड़ने की परवाह करें। – blackSmith

+2

कोई ज़रूरत नहीं है, डाउनवोट तीर के लिए टूलटिप आपको पहले से ही बताता है कि आपको – Clive

+0

@Clive: टिप के लिए धन्यवाद। हालांकि अगर मैं जावा का उपयोग करके हेडर तक पहुंचने के बारे में जान सकूं, तो मैं इसे पोस्ट नहीं करता। स्पष्टता के लिए मैं सवाल संपादित कर सकता हूं। आखिर में मैं स्वीकार नहीं कर सकता कि यह 'उपयोगी नहीं है' क्योंकि एसओ में बहुत सारे 'java.lang.OutOfMemoryError: Java Heap space'' BufferedImage' प्रकार के प्रश्नों का उपयोग करते समय। – blackSmith

उत्तर

11

छवियों को पढ़ने और छेड़छाड़ करने के लिए जावा एपीआई वास्तव में स्ट्रीम-आधारित नहीं हैं जैसा आपको लगता है। ImageInputStream केवल एक सुविधा रैपर है जो byte एस और विभिन्न इनपुट से अन्य आदिम प्रकारों को पढ़ने की अनुमति देता है (RandomAccessFile एस, InputStream एस आदि)।

मैं "पिक्सेल स्ट्रीम" पढ़ने के लिए एपीआई बनाने के बारे में सोच रहा हूं, ताकि अधिक मेमोरी का उपयोग किये बिना प्रोसेसिंग फ़िल्टर की श्रृंखला को अनुमति दी जा सके। लेकिन प्रयास कभी भी प्रयास के लायक होने के लिए पर्याप्त गंभीर नहीं रहा है। अगर आप अधिक विचार सुनना चाहते हैं या कामकाजी कार्यान्वयन करना चाहते हैं तो मुझे किराए पर लेने के लिए स्वतंत्र महसूस करें।

  1. उपयोग BufferedImage के रूप में है, और ImageIO एपीआई को पढ़ने के लिए: ;-)

    फिर भी, के रूप में मैं इसे देख, आप अपने अंतिम लक्ष्य को प्राप्त करने के लिए कई विकल्प हैं, बड़ी छवियों को संसाधित करने में सक्षम होने के लिए स्मृति को बचाने के लिए छोटे भागों में एक छवि। यह कुछ प्रारूपों के लिए काफी कुशल होगा, कार्यान्वयन के कारण अन्य प्रारूपों के लिए कम कुशल होगा (यानी डिफ़ॉल्ट JPEGImageReader जावा क्षेत्र में छोटे क्षेत्र को सौंपने से पहले मूल छवि में पूरी छवि को पढ़ेगा, लेकिन PNGImageReader ठीक हो सकता है)।

    की तर्ज पर

    कुछ:

    ImageInputStream stream = ImageIO.createImageInputStream(input); 
    ImageReader reader = ImageIO.getImageReaders(stream).next(); // TODO: Test hasNext() 
    reader.setInput(stream); 
    
    int width = reader.getWidth(0); 
    int height = reader.getHeight(0); 
    
    ImageReadParam param = reader.getDefaultReadParam(); 
    
    for (int y = 0; y < height; y += 100) { 
        for (int x = 0; x < width; x += 100) { 
          param.setSourceRegion(new Rectangle(x, y, 100, 100)); // TODO: Bounds check 
    
          // Read a 100 x 100 tile from the image 
          BufferedImage region = reader.read(0, param); 
    
          // ...process region as needed... 
        } 
    } 
    
  2. एक स्मृति मैप किए गए बफर में, एक ही बार में पूरी छवि पढ़ें। इस उद्देश्य के लिए मैंने कुछ experimental classes कोशिश करने के लिए स्वतंत्र महसूस किया है (nio का उपयोग करके)। एक शुद्ध स्मृति छवि को पढ़ने से पढ़ने धीमा हो जाएगा, और प्रसंस्करण भी धीमा हो जाएगा। लेकिन यदि आप एक समय में छवि के छोटे क्षेत्रों पर गणना कर रहे हैं, तो यह कुछ अनुकूलन के साथ स्मृति के रूप में तेज़ी से हो सकता है। मैंने इन कक्षाओं का उपयोग करते हुए 32 एमबी जेवीएम में 1 जीबी छवियां पढ़ी हैं (वास्तविक स्मृति खपत निश्चित रूप से कहीं अधिक है)।

    फिर, यहाँ एक उदाहरण है:

    ImageInputStream stream = ImageIO.createImageInputStream(input); 
    ImageReader reader = ImageIO.getImageReaders(stream).next(); // TODO: Test hasNext() 
    reader.setInput(stream); 
    
    int width = reader.getWidth(0); 
    int height = reader.getHeight(0); 
    ImageTypeSpecifier spec = reader.getImageTypes(0).next(); // TODO: Test hasNext(); 
    
    BufferedImage image = MappedImageFactory.createCompatibleMappedImage(width, height, spec) 
    
    ImageReadParam param = reader.getDefaultReadParam(); 
    param.setDestination(image); 
    
    image = reader.read(0, param); // Will return same image as created above 
    
    // ...process image as needed... 
    
  3. कुछ प्रारूपों, असम्पीडित TIFF की तरह, बीएमपी, पीपीएम आदि, फ़ाइल में पिक्सल एक तरह से है कि यह करने के लिए उन्हें सीधे स्मृति नक्शा संभव होगा रहता है उन्हें कुशल बनाने के लिए। कुछ काम की आवश्यकता है, लेकिन संभव होना चाहिए। टीआईएफएफ टाइल्स का भी समर्थन करता है जो मदद की हो सकती है। मैं इस विकल्प को एक अभ्यास के रूप में छोड़ दूंगा, जो ऊपर से जुड़े वर्गों को शुरुआती बिंदु या प्रेरणा के रूप में उपयोग करने के लिए स्वतंत्र महसूस करता हूं। ;-)

  4. जेएआई में कुछ ऐसा हो सकता है जो आपकी मदद कर सके। मैं ओरेकल द्वारा कई अनसुलझा बग और प्यार और विकास की कमी के कारण एक बड़ा प्रशंसक नहीं हूं। लेकिन बाहर की जाँच करने लायक है। मैं सोचता हूं उनके पास टाइल करने योग्य और डिस्क-आधारित RenderedImage एस के लिए भी समर्थन है। फिर, मैं आपके लिए आगे का पता लगाने के लिए इस विकल्प को छोड़ दूंगा।

+0

प्रबंधनीय लगता है, मैं वास्तव में दोनों उत्तरों से पहले कहीं नहीं था। चलिए देखते हैं कि मैं अपने '(inspi | explo) राशन' के साथ कितना दूर जा सकता हूं। निश्चित रूप से आप फेलो से समर्थन लेना होगा। भर्ती प्रस्ताव के लिए +1 वैसे, हालांकि मैं सिर्फ एक हूँ – blackSmith

4

स्मृति समस्या निश्चित रूप से डिकोडिंग प्रक्रिया के साथ ही संबंधित नहीं है, लेकिन BufferedImage के रूप में स्मृति में पूर्ण छवि को संग्रहीत करने के साथ। यह उत्तरोत्तर एक PNG छवि को पढ़ने के लिए संभव है, लेकिन:

  • यह केवल मामूली "मात्रा", में संगठन से संबंधित है तो तथ्य यह है कि PNG फ़ाइलें पंक्ति-दर-पंक्ति इनकोड, और इतने के साथ वे सिद्धांत में हो सकते हैं- लाइन-दर-रेखा पढ़ें।

  • interlaced PNG का के मामले में ऊपर धारणा टूट जाता है - लेकिन एक इंटरलेस्ड प्रारूप

  • कुछ पीएनजी पुस्तकालयों प्रगतिशील (पंक्ति-दर-पंक्ति) डिकोडिंग के लिए अनुमति जबकि में संग्रहीत विशाल PNG छवियाँ के लिए उम्मीद नहीं करनी चाहिए (उदाहरण: libpng), मानक जावा एपीआई आपको वह नहीं देता है।

मुझे लगता है कि समस्या का सामना करना पड़ रहा था और मैं अपने खुद के जावा पुस्तकालय कोडिंग समाप्त हो गया: PNGJ। यह काफी परिपक्व है, यह लाइन द्वारा पीएनजी छवियों को लाइन पढ़ने, स्मृति खपत को कम करने, और उन्हें उसी तरह लिखने की अनुमति देता है (यहां तक ​​कि अंतःस्थापित पीएनजी भी पढ़ा जा सकता है, लेकिन इस मामले में स्मृति समस्या दूर नहीं जाएगी।) यदि आपको केवल आवश्यकता है कुछ "स्थानीय" छवि प्रसंस्करण करने के लिए (वर्तमान मूल्य और पड़ोसियों के आधार पर प्रत्येक पिक्सेल मान संशोधित करें, और इसे वापस लिखें) इससे मदद मिलनी चाहिए।

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