halil
halil

Reputation: 800

get average image of a set of images in java

I have a set of meteorological RGB type BufferedImages. I want to get average image of them. By that, I mean get average value of each pixel and make a new image out of those values. What I tried is this:

public void getWaveImage(BufferedImage input1, BufferedImage input2){
   // images are of same size that's why i'll use first one's width and height
   int width = input1.getWidth(), height = input1.getHeight();

   BufferedImage output = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

   int[] rgb1 = input1.getRGB(0, 0, width, height, new int[width * height], 0, width);
   int[] rgb2 = input2.getRGB(0, 0, width, height, new int[width * height], 0, width);
   for(int i=0; i<width; i++){
      for(int j=0; j<height; j++){
         int rgbIndex = i * width + j;
         rgb1[rgbIndex] = (rgb1[rgbIndex] + rgb2[rgbIndex]) / 2;
      }
   }

   output.setRGB(0, 0, width, height, rgb1, 0, width);
   return output;
}

What am I doing wrong? Thank you in advance.

input1:

enter image description here

input2:

enter image description here

output:

enter image description here

Upvotes: 1

Views: 1329

Answers (3)

Nahuel Fouilleul
Nahuel Fouilleul

Reputation: 19315

another solution can be to replace

rgb1[rgbIndex] = (rgb1[rgbIndex] + rgb2[rgbIndex]) / 2;

with

rgb1[rgbIndex] = ((rgb1[rgbIndex]>>1)&0x7f7f7f7f)+((rgb2[rgbIndex]>>1)&0x7f7f7f7f)+(rgb1[rgbIndex]&rgb2[rgbIndex]&0x01010101);

binary right shift to divide by 2, last member of the sum to handle the case of two odd numbers.

Upvotes: 1

weston
weston

Reputation: 54791

You want the average of each component of the colour, average red, average green, average blue.

Instead you are averaging the whole int.

Color c1 = new Color(rgb1[rgbIndex]);
Color c2 = new Color(rgb2[rgbIndex]);
Color cA = new Color((c1.getRed()   + c2.getRed())/2,
                     (c1.getGreen() + c2.getGreen())/2,
                     (c1.getBlue()  + c2.getBlue())/2);
rgb1[rgbIndex] = cA.getRGB();

This may not be the most efficient due to creating so many objects, so a more direct approach is like so:

public static int average(int argb1, int argb2){
   return (((argb1       & 0xFF) + (argb2       & 0xFF)) >> 1)       | //b
          (((argb1 >>  8 & 0xFF) + (argb2 >>  8 & 0xFF)) >> 1) << 8  | //g
          (((argb1 >> 16 & 0xFF) + (argb2 >> 16 & 0xFF)) >> 1) << 16 | //r
          (((argb1 >> 24 & 0xFF) + (argb2 >> 24 & 0xFF)) >> 1) << 24;  //a
}

Usage:

rgb1[rgbIndex] = average(rgb1[rgbIndex], rgb2[rgbIndex]);

Upvotes: 5

assylias
assylias

Reputation: 328619

If you have:

int rgb1, rgb2; //the rgb value of a pixel in image 1 and 2 respectively

The "average" color would be:

int r = (r(rgb1) + r(rgb2)) / 2;
int g = (g(rgb1) + g(rgb2)) / 2;
int b = (b(rgb1) + b(rgb2)) / 2;

int rgb = ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF) << 0);

with the following "helper" methods:

private static int r(int rgb) { return (rgb >> 16) & 0xFF; }
private static int g(int rgb) { return (rgb >> 8) & 0xFF; }
private static int b(int rgb) { return (rgb >> 0) & 0xFF; }

Alternatively you can use the Color class if you don't want to deal with bitwise operations.

Upvotes: 3

Related Questions