user3526114
user3526114

Reputation: 3

Averaging pixel data from array

I'm trying to tackle a problem where an image is read. I need to exclude the Blue channel in the pixel so the it will result in an RG image.

This is what I have so far and not working D;

Would I need to create a new BufferedImage and apply each averaged pixel (Without the blue channel) to it? I'm not sure how to do it though.

Upvotes: 0

Views: 801

Answers (2)

Markus A.
Markus A.

Reputation: 12742

For starters, change your second-to-last line of code to this and see if it helps:

image.setRGB(i, j, (redData[i][j] << 16) | (greenData[i][j] << 8));

But with this, you will end up with an image that is the same size as the original, except that you drop the blue channel and you average over the other channels (sort-of like a blur), but only in the top left corner of each 2x2-block.

If you want to actually create an image of a quarter size, you do indeed need to create a new BufferedImage with half the width and height and then change the above mentioned line to:

newImage.setRGB(i/2, j/2, (redData[i][j] << 16) | (greenData[i][j] << 8));

Here's an updated version of your code that should do it (untested):

public static BufferedImage isolateBlueChannelAndResize(BufferedImage image) {
    int imageWidth  = image.getWidth();
    int imageHeight = image.getHeight();
    // Round down for odd-sized images to prevent indexing outside image
    if ((imageWidth  & 1) > 0) imageWidth --;
    if ((imageHeight & 1) > 0) imageHeight--;

    BufferedImage newImage = new BufferedImage(imageWidth/2, imageHeight/2, image.getType());

    for (int i = 0; i < imageWidth; i += 2) {
        for (int j = 0; j < imageHeight; j += 2) {
            int r1 = (image.getRGB(i  , j  ) >> 16) & 0xff;
            int r2 = (image.getRGB(i+1, j  ) >> 16) & 0xff;
            int r3 = (image.getRGB(i  , j+1) >> 16) & 0xff;
            int r4 = (image.getRGB(i+1, j+1) >> 16) & 0xff;
            int red = (r1 + r2 + r3 + r4 + 3) / 4;   // +3 rounds up (equivalent to ceil())

            int g1 = (image.getRGB(i  , j  ) >>  8) & 0xff;
            int g2 = (image.getRGB(i+1, j  ) >>  8) & 0xff;
            int g3 = (image.getRGB(i  , j+1) >>  8) & 0xff;
            int g4 = (image.getRGB(i+1, j+1) >>  8) & 0xff;
            int green = (g1 + g2 + g3 + g4 + 3) / 4;   // +3 rounds up (equivalent to ceil()) 

            newImage.setRGB(i/2, j/2, (red << 16) | (green << 8));
        }
    }

    return newImage;
}

Upvotes: 2

Jared
Jared

Reputation: 940

I really think the easier way is to use the Color class:

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class AverageOutBlue {
    public static final float AVG_FACTOR = 1f / (4f * 255f);

    public static BufferedImage processImage(final BufferedImage src) {
        final int w = src.getWidth();
        final int h = src.getHeight();

        final BufferedImage out = new BufferedImage(w / 2, h / 2, src.getType());

        for (int i = 0; i < w; i += 2)
            for (int j = 0; j < h; j += 2) {
                final Color color = avgColor(src, i, j);
                out.setRGB(i / 2, j / 2, color.getRGB());
            }

        return out;
    }

    private static Color avgColor(final BufferedImage src, final int i,
        final int j) {

        final Color c1 = new Color(src.getRGB(i, j));
        final Color c2 = new Color(src.getRGB(i + 1, j));
        final Color c3 = new Color(src.getRGB(i + 1, j));
        final Color c4 = new Color(src.getRGB(i + 1, j + 1));

        final float r = (c1.getRed() + c2.getRed() + c3.getRed() + c4.getRed())
                            * AVG_FACTOR;
        final float g = (c1.getGreen() + c2.getGreen() + c3.getGreen() + 
                            c4.getGreen()) * AVG_FACTOR;

        return new Color(r, g, 0f);
    }
}

Upvotes: 0

Related Questions