문제

I need to toggle on/off RGB channels of an image, but I am stuck and my code is buggy.

Can you help me figure out how to do this the right way? This is my code:

The function channels is called when 1 of 3 checkboxes has changed its state and provides the arguments which are true == selected

public void channels(boolean red, boolean green, boolean blue) {
    if (this.img != null) {// checks if the image is set
        char r = 0xFF, g = 0xFF, b = 0xFF;
        if (red == false) {
            r = 0x00;
        }
        if (green == false) {
            g = 0x00;
        }
        if (blue == false) {
            b = 0x00;
        }
        BufferedImage tmp = new BufferedImage(
                img.getWidth(),
                img.getHeight(),
                BufferedImage.TYPE_INT_RGB);
        for (int i = 0; i < img.getWidth(); i++) {
            for (int j = 0; j < img.getHeight(); j++) {
                int rgb = img.getRGB(i, j);
                int red = (rgb >> 16) & r;
                int green = (rgb >> 8) & g;
                int blue = (rgb >> 0) & b;
                int gbr = (red << 16) | (green << 8) | blue;// EDITED
                tmp.setRGB(i, j, gbr);
            }
        }
        img = tmp;
        repaint();
    } else {
        //show error
    }
}

Thank you for your help!

도움이 되었습니까?

해결책 2

It looks like you're shifting in the bits wrong. Shouldn't it be: int gbr = (red << 16) | (green << 8) | blue;? You basically want to shift back in the same order as how you shifted out to begin with.

Also, once you have cleared the corresponding colour, there's no way for you to get it back. You'll need to store a copy of the original image somewhere. When it's time to turn the channel back on, simply copy the original pixel from the original image back.

Assuming that you have the original image stored somewhere as origImg, I would modify your for loop so that if the channel is toggled on, copy from the original image.

for (int i = 0; i < img.getWidth(); i++) {
    for (int j = 0; j < img.getHeight(); j++) {
        int rgb = img.getRGB(i, j);
        int origRGB = origImg.getRGB(i, j);              
        int redPixel = red ? (origRGB >> 16) & r : (rgb >> 16) & r;
        int greenPixel = green ? (origRGB >> 8) & g : (rgb >> 8) & g;
        int bluePixel = blue ? origRGB & b : rgb & b;
        int gbr = (redPixel << 16) | (greenPixel << 8) | bluePixel;
        tmp.setRGB(i, j, gbr); 
   }
}

다른 팁

How about this optimized version, with a lot less bit shifting?

public void channels(boolean showRed, boolean showGreen, boolean showBlue) {
    if (this.origImg!= null) {// checks if the image is set
        int channelMask = 0xff << 24 | (showRed ? 0xff : 0) << 16 | (showGreen ? 0xff : 0) << 8 | (showBlue ? 0xff : 0);

        BufferedImage tmp = new BufferedImage(origImg.getWidth(), origImg.getHeight(), BufferedImage.TYPE_INT_RGB);

        for (int i = 0; i < origImg.getWidth(); i++) {
            for (int j = 0; j < origImg.getHeight(); j++) {
                int rgb = origImg.getRGB(i, j);
                tmp.setRGB(i, j, rgb & channelMask);
            }
        }

        img = tmp;
        repaint();
    } else {
        //show error
    }
}

A faster approach yet, would probably be to use a channeled Raster, or at least a Raster configuration that allows band sub-sampling (see Raster.createChild(...) method, especially the last parameter).

LookupOp, as mentioned by @trashgod is also a good idea, and probably faster than the getRGB()/setRGB() approach.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top