2012-06-12 13 views
12

मैं जावा एप्लिकेशन के हिस्से पर काम कर रहा हूं जो एक बाइट सरणी के रूप में एक छवि लेता है, इसे java.awt.image.BufferedImage उदाहरण में पढ़ता है और इसे प्रोसेसिंग के लिए किसी तृतीय-पक्ष लाइब्रेरी में भेजता है।क्या BufferedImage उदाहरणों की तुलना करने का कोई आसान तरीका है?

एक यूनिट परीक्षण के लिए, मैं एक छवि (डिस्क पर फ़ाइल से) लेना चाहता हूं और जोर देकर कहता हूं कि यह उसी छवि के बराबर है जो कोड द्वारा संसाधित किया गया है।

  • मेरे उम्मीदBufferedImageImageIO.read(URL) का उपयोग कर डिस्क पर एक PNG फ़ाइल से पढ़ा जाता है।
  • मेरा परीक्षण कोड उसी फ़ाइल को BufferedImage में पढ़ता है और लिखता है कि परीक्षण के तहत सिस्टम को प्रदान करने के लिए पीएनजी के रूप में बाइट सरणी में लिखा जाता है।

जब परीक्षण के अंतर्गत प्रणाली एक नया BufferedImage मैं बात पर जोर देना है कि दो छवियों एक सार्थक तरीके से बराबर हैं चाहते हैं बाइट सरणी लिखता है। equals() का उपयोग करना (Object से विरासत में मिला) काम नहीं करता है (बेशक)। BufferedImage.toString() मानों की तुलना करना भी काम नहीं करता है क्योंकि आउटपुट स्ट्रिंग में ऑब्जेक्ट संदर्भ जानकारी शामिल है।

क्या किसी को भी कोई शॉर्टकट पता है? मैं एक बड़े आवेदन के एक छोटे से हिस्से में एक इकाई परीक्षण के लिए एक थर्ड-पार्टी लाइब्रेरी नहीं लेना पसंद करूंगा।

+0

क्या आप समझा सकते हैं कि वास्तव में'equals() 'क्यों काम नहीं करेगा? –

+1

@ जेककिंग: यदि यह ऑब्जेक्ट से विरासत में मिला है, तो यह काम नहीं करेगा क्योंकि यह केवल ऑब्जेक्ट पहचान करता है। – Thilo

+2

क्या आप बस बाइट एरे की तुलना नहीं कर सकते (जिसमें पीएनजी है)? – Thilo

उत्तर

13

यह सबसे अच्छा तरीका है। यह देखने के लिए एक चर रखने की आवश्यकता नहीं है कि छवि अभी भी बराबर है या नहीं। झूठी अगर स्थिति तुरंत झूठी वापसी।शॉर्ट-सर्किट मूल्यांकन ट्रम्पलेटलिक के answer में मामला विफल होने के बाद पिक्सल पर समय लूपिंग को बचाने में मदद करता है।

/** 
* Compares two images pixel by pixel. 
* 
* @param imgA the first image. 
* @param imgB the second image. 
* @return whether the images are both the same or not. 
*/ 
public static boolean compareImages(BufferedImage imgA, BufferedImage imgB) { 
    // The images must be the same size. 
    if (imgA.getWidth() == imgB.getWidth() && imgA.getHeight() == imgB.getHeight()) { 
    int width = imgA.getWidth(); 
    int height = imgA.getHeight(); 

    // Loop over every pixel. 
    for (int y = 0; y < height; y++) { 
     for (int x = 0; x < width; x++) { 
     // Compare the pixels for equality. 
     if (imgA.getRGB(x, y) != imgB.getRGB(x, y)) { 
      return false; 
     } 
     } 
    } 
    } else { 
    return false; 
    } 

    return true; 
} 
+0

अच्छा और सरल समाधान! ठीक वही जो मेरे द्वारा खोजा जा रहा था! – Waylander

3

तुलना के लिए आप अपना खुद का दिनचर्या लिख ​​सकते हैं!

int width; 
int height; 
boolean imagesEqual = true; 

if(image1.getWidth() == (width = image2.getWidth()) && 
    image1.getHeight() == (height = image2.getHeight())){ 

    for(int x = 0;imagesEqual == true && x < width; x++){ 
     for(int y = 0;imagesEqual == true && y < height; y++){ 
      if(image1.getRGB(x, y) != image2.getRGB(x, y)){ 
       imagesEqual = false; 
      } 
     } 
    } 
}else{ 
    imagesEqual = false; 
} 

यह एक तरीका होगा !!!

+2

आकारों के मिलान होने पर भी झूठी होने की आवश्यकता है। केवल 'if' ब्लॉक के अंदर बुलियन को सही पर सेट करें। – Thilo

+0

ग्रेट प्वाइंट, Ive संपादित! – trumpetlicks

+1

@trumpetlicks इसके अलावा, 'ब्रेक' कथन बहुत कुछ नहीं करेगा, आपने 'लूप' के लिए नेस्टेड किया है। – Jeffrey

0

मैं एक जानवर बल "लूप करना" के अलावा कुछ भी नहीं सोच सकते हैं:

BufferedImage bi1, bi2, ... 
    ... 
    Raster r1 = bi1.getData(); 
    DataBuffer db1 = r1.getDataBuffer(); 
    if (db1.getSize() != db2.getSize()) 
    ... 
    for (int i = 0; i < db1.getSize(); i++) { 
    int px = db1.getElem(i); 
    } 
+0

अच्छा जवाब, लेकिन यह स्मृति को दो बार उपयोग करता है क्योंकि यह पूरी छवि को दूसरे बफर में कॉपी करता है! कम वास्तविक दिनचर्या कॉल करने के लिए तेजी से करने का मौका हो सकता है :-) परीक्षण के बिना जानने का कोई तरीका नहीं !!! – trumpetlicks

+0

@trumpetlicks +1 * "परीक्षण के बिना जानने का कोई तरीका नहीं !!!" * मुझे संदेह है कि यह 'getRGB()' प्रति पिक्सेल की तुलना में * तेज * होगा, लेकिन परीक्षण इसे सॉर्ट करेगा। –

+0

@AndrewThompson - वास्तव में यह सुनिश्चित नहीं है कि वह डीबी 1 को बुला रहा है। प्रत्येक पुनरावृत्ति को आकार दें, साथ ही साथ संभावित रूप से 4 डेटा प्रतियां। 1 आर 1 बनाने के लिए, दूसरा डीबी 1 के लिए, और आर 2 और डीबी 2 के लिए एक ही 2। फिर उसके पास डीबी 1.getElem (i) भी है। दरअसल यह वास्तव में धीमा हो जाएगा, क्योंकि वह सरणी के भीतर दोनों तत्वों को प्राप्त करने के लिए नियमित रूप से बुला रहा है। db1.getSize() छवि की वापसी (चौड़ाई * ऊंचाई) जा रहा है। तो वह न केवल डेटा की प्रतिलिपि बना रहा है, बल्कि लूप के भीतर उसी दिनचर्या को बुला रहा है। वह भी तुलना ऑपरेशन भी नहीं कर रहा है !!! – trumpetlicks

5

गति एक समस्या है, और दोनों BufferedImages ही बिट गहराई, व्यवस्था, आदि के हैं (यदि जो लगता है जैसे कि यह यहाँ सही होना चाहिए) आप यह कर सकते हैं: यह है जो टाइप बाहर

DataBuffer dbActual = myBufferedImage.getRaster().getDataBuffer(); 
DataBuffer dbExpected = bufferImageReadFromAFile.getRaster().getDataBuffer(); 

आंकड़ा है, जैसे एक DataBufferInt

DataBufferInt actualDBAsDBInt = (DataBufferInt) dbActual ; 
DataBufferInt expectedDBAsDBInt = (DataBufferInt) dbExpected ; 

आकार पर बराबरी और DataBuffers के तट के लिए कुछ "विवेक चेकों" करते हैं, तो पाश

for (int bank = 0; bank < actualDBAsDBInt.getNumBanks(); bank++) { 
    int[] actual = actualDBAsDBInt.getData(bank); 
    int[] expected = expectedDBAsDBInt.getData(bank); 

    // this line may vary depending on your test framework 
    assertTrue(Arrays.equals(actual, expected)); 
} 

यह जितनी जल्दी के करीब है के रूप में आप आप हथियाने रहे हैं कारण प्राप्त कर सकते हैं एक समय में डेटा का एक हिस्सा, एक समय में नहीं।

+0

वही बिट-गहराई, व्यवस्था, आदि ... एक बहुत बड़ा है। बस कल एक लड़के के सवाल का जवाब दिया जहां वह अनिवार्य रूप से छवियों की तुलना कर रहा था, और उसने पाया कि एक ARGB_8888 था और दूसरा RGB_565 था। ये बड़ी धारणाएं हैं। यदि आप पैरामीटर सत्य हैं, तो यह वास्तव में सही है, हालांकि यह सबसे तेज़ तरीका होगा :-) – trumpetlicks

+0

चूंकि यह एक यूनिट टेस्ट है, ऐसा लगता है कि उसकी टेस्ट छवि एक ही बिट-गहराई आदि होनी चाहिए लेकिन आपसे सहमत हैं कि, सामान्य, यह एक धारणा का एक सा है। – user949300

0

आप imageio के माध्यम से OutputStream के माध्यम से byte[] पर उस छवि को लिख सकते हैं। मेरे कोड में, यह अधिक या इस तरह कम दिखता है:

byte[] encodeJpegLossless(BufferedImage img){...using imageio...} 
... 
Assert.assertTrue(Arrays.equals(encodeJpegLossless(img1) 
           ,encodeJpegLossless(img2) 
           ) 
       ); 
1

मैं ग्रूवी में function that equals by pixels बदल गया है, से सहायता मिलेगी:

boolean imagesAreEqual(BufferedImage image1, BufferedImage image2) { 
    if (image1.width != image2.width || image1.height != image2.height) { 
     return false 
    } 
    for (int x = 1; x < image2.width; x++) { 
     for (int y = 1; y < image2.height; y++) { 
      if (image1.getRGB(x, y) != image2.getRGB(x, y)) { 
       return false 
      } 
     } 
    } 
    return true 
} 
संबंधित मुद्दे

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