Isolating Red/Green/Blue Channel in Java BufferedImage

KernelPanic picture KernelPanic · May 22, 2013 · Viewed 7.8k times · Source

How to isolate red/green/blue channel in BufferedImage: I have following code that does NOT work:`

public static BufferedImage isolateChannel(BufferedImage image,
        EIsolateChannel channel)
{
    BufferedImage result=new BufferedImage(image.getWidth(),
            image.getHeight(),
            image.getType());
    int iAlpha=0;
    int iRed=0;
    int iGreen=0;
    int iBlue=0;
    int newPixel=0;

    for(int i=0; i<image.getWidth(); i++)
    {
        for(int j=0; j<image.getHeight(); j++)
        {
            iAlpha=new Color(image.getRGB(i, j)).getAlpha();
            iRed=new Color(image.getRGB(i, j)).getRed();
            iGreen=new Color(image.getRGB(i, j)).getGreen();
            iBlue=new Color(image.getRGB(i, j)).getBlue();

            if(channel.equals(EIsolateChannel.ISOLATE_RED_CHANNEL))
            {
                newPixel=iRed;
            }

            if(channel.equals(EIsolateChannel.ISOLATE_GREEN_CHANNEL))
            {
                newPixel=iGreen;
            }

            if(channel.equals(EIsolateChannel.ISOLATE_BLUE_CHANNEL))
            {
                newPixel=iBlue;
            }

            result.setRGB(i,
                    j,
                    newPixel);
        }
    }

    return result;
}`

By isolating channel I mean that if red channel is selected for isolation, for example, that only red component of picture is shown!

Answer

Extreme Coders picture Extreme Coders · May 22, 2013

Color in java is defined in a packed integer,that is in a 32 bit integer the first 8 bits are alpha, next 8 are red, next 8 are green and last 8 are blue.

Suppose the following is an 32 bit integer representing a color.Then,

AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB
^Alpha   ^Red     ^Green   ^Blue

That is, each of alpha, red, green and blue are basically 8 bits with values from 0 to 255 (the color range). So when you would want to combine these individual components back into the 32 bit integer color you should write

color=alpha<<24 | red<<16 | green<<8 | blue

So as per the rules change the code to the following

if(channel.equals(EIsolateChannel.ISOLATE_RED_CHANNEL))
{
    newPixel = newPixel | iRed<<16; 
    //Can also write newPixel=iRed , since newPixel is always 0 before this
}

if(channel.equals(EIsolateChannel.ISOLATE_GREEN_CHANNEL))
{
    newPixel = newPixel | iGreen<<8;
}

if(channel.equals(EIsolateChannel.ISOLATE_BLUE_CHANNEL))
{
    newPixel = newPixel | iBlue;
}

Note : I have ORed the newPixel before each component to allow display of multiple channels simultaneously, i.e you could display red and green with blue turned off.


UPDATE

The second error you are getting is due to the fact that you are not resetting the value of newPixel after each iteration. So to fix it add the line newPixel=0 within the loop. Your code should be

newPixel=0; //Add this line
iAlpha=new Color(img.getRGB(x, y)).getAlpha();
iRed=new Color(img.getRGB(x, y)).getRed();
iGreen=new Color(img.getRGB(x, y)).getGreen();
iBlue=new Color(img.getRGB(x, y)).getBlue();

For added efficiency I would suggest using bitshifts for obtaining the red, green, blue, and the alpha.

int rgb = img.getRGB(x,y);
iAlpha = rgb>>24 & 0xff;
iRed = rgb >>16 & 0xff;
iGreen = rgb>>8 & 0xff;
iBlue = rgb & 0xff;

This code would run faster as it does not creates 4 Color objects for each pixel in the source image