views:

399

answers:

3

I have a BufferedImage of type TYPE_INT_BGR. I need to do a pixel-by-pixel comparison to another BufferedImage to compute the "distance" between the two images. I have something that works, but is slow. I get a pixel from the "reference" image, break it up into RGB bytes with:

    int pixel = referenceImage.getRGB(col, row);
    int red   = (pixel >> 16) & 0xff;
    int green = (pixel >> 8) & 0xff;
    int blue  = (pixel) & 0xff;

I compare the r/g/b values to the corresponding pixel of the candidate image, and sum up the squares the differences.

Is there a faster way to do this kind of comparison? Peeking into the JRE source, I see that BufferedImage.getRGB() is actually ORing the constituent RGB values from the raster together, which is wasteful for my purposes, since I'm just breaking it down into bytes again.

I'm going to try doing that directly, but I wonder if there is not a better way of doing this, either via a Java or 3rd party API that I might have missed.

+1  A: 

If both images use the same color model and sampling, you can perform your comparison on the DataBuffer of the raster, which will be a little faster.

Mikeb
Yes, both images use the same color model and sampling. Presumably with DataBuffer I will still need to do the bit shifting, but perhaps at least avoid ORing the values back together.
Caffeine Coma
If it helps at all, all of the images I am working with are "offscreen"; one is read in from a JPG, the other one is constructed from drawing into a Graphics2D. I have never used VolatileImage before, I will check it out.
Caffeine Coma
+2  A: 

Reading data from a VolatileImage will not be faster. What makes VolatileImages "faster" is that they use accelerated (VRAM) memory instead of system (RAM) memory for drawing images. However, when doing a read, it may need to access memory over another bus and is slower than system memory for those operations.

The fastest way to compare BufferedImages would be to use integer comparisons the way you discuss in your post, but as you mention you can't use getRGB for performance reasons. You can get a batch of pixels into an array, but overall you should probably just peek into the Raster and DataBuffer for performance.

Kristopher Ives
You are right; Volatile is a bad suggestion. I've edited that out. Sadly I can't downvote my answer.
Mikeb
Your answer was good about the DataBuffer comparison :)
Kristopher Ives
+1  A: 

Have you considered using Java2D to create a new image being the difference between the two images you have, and then analyse the difference image instead?

My initial approach would be taking the negative of image A and add image B.

Thorbjørn Ravn Andersen
This is an excellent idea :)
Kristopher Ives
This seems like a great idea, but I haven't had much luck finding examples. I assume I'd need to implement java.awt.CompositeContext. The only implementation of that I see is SunCompositeContext, and unfortunately the source is not provided.
Caffeine Coma