Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

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.

If breaking down to bytes + loading extra classes is the problem, try this:

Getting the BufferedImage value form a RGB pixel value

img = 65536*R + 256*G + B - 16777216;  

Getting a RGB value from a BufferedImage value img

R=  Math.round((((371*img)+24576000000) / 96000000)
G=  Math.round((65536 + 0.003906*img - 256*R));
B=  Math.round((65536*R + 256*G -img - 16777216));

I am not sure if this is a better/faster way to do it, but it is another alternative method that does not use any extra classes, and is a straight math process (or a hack)... This may become useful on some occasions (please double-check since it is my own method that I didn't have enough time to play with).

I don't know about the kind of comparison you needed between the pixel values, so this is how far this post goes... I hope someone actually finds this helpful!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top