Search code examples
javaimage-processingcolorsbufferedimagecolor-channel

Isolating Red/Green/Blue Channel in Java BufferedImage


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!


Solution

  • 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