简体   繁体   中英

How to apply grayscale image mask to a rgb image in java

I was recommended to separate this question from another one. Here is the original:

How to change white background for black

After some image processes i get a binary image, but the borders are so hard so i apply a gaussian filter to get a soft one. The result is a grayscale image. I need to apply this image as a mask for another one, none of them has an alpha channel so mix of colors need to be done without this value. I am using Marvin Framework to do the job but Marvin does not has a plugin for it, so i code one, this is it:

@Override public void process(MarvinImage _imageIn, MarvinImage _imageOut, MarvinAttributes attrOut, MarvinImageMask _mask, boolean previewMode) {

    MarvinImage mask = _imageIn;
    MarvinImage image = _imageOut;

    for(int y=0; y<mask.getHeight(); y++){
        for(int x=0; x<mask.getWidth(); x++){

            //ya que está en grayscale, los 3 valores son los mismos
            int r1 = mask.getIntComponent0(x, y);
            int g1 = mask.getIntComponent1(x, y);
            int b1 = mask.getIntComponent2(x, y);

            int r2 = image.getIntComponent0(x, y);
            int g2 = image.getIntComponent1(x, y);
            int b2 = image.getIntComponent2(x, y);

            //al color de salida, le asignamos la luminicencia de la imagen mascara
            int r = 0, g = 0, b = 0;
            if(r1 > 0 || r2 > 0){
                r = r1*r2/Math.max(r1, r2);
            }

            if(g1 > 0 || g2 > 0){
                g = g1*g2/Math.max(g1, g2);
            }

            if(b1 > 0 || b2 > 0){
                b = b1*b2/Math.max(b1, b2);
            }

            image.setIntColor(x, y, r, g, b);
        }
    }
}

But this code has a little bug that i couldn't resolve. When the rgb image has a white, the color result is not combined very well, it does not get darker. What i am looking for is something one can achieve using gimp, where there is a 2 layer image, the bottom one is the rgb image and the upper one is the grayscale mask, then in this layer we use the function color to alpha, using the white color as a target. The result is the next:

金普混合

Whit the algorithm is the next:

算法组合

The difference is pretty obious. Here are the two original images for testing:

彩色图像 灰度蒙版

You just need to do an alpha combination of the image with the mask. Basically the output image pixel is:

output_image(x,y) = input_image(x,y) * PI + mask_image(x,y) * PM

Where PI and PM are the percentage of input and mask images in the output pixel, respectively. PI + PM = 1 (100%)

Example:

For black pixels in the mask:

PM = 1 - (grayscalePixel / 255) → 1 - (0 / 255) = 1

For white pixels:

PM = 1 - (grayscalePixel / 255) → 1 - (255 / 255) = 0

For a gray pixel:

PM = 1 - (grayscalePixel / 255) → 1 - (127 / 255) = 0.5

Finally:

PI = 1 - PM;

OUTPUT 1:

在此处输入图片说明

Source code:

public class GrayScaleMask {

    public GrayScaleMask(){

        MarvinImage image = MarvinImageIO.loadImage("./res/grayscaleMask_input.png");
        MarvinImage mask = MarvinImageIO.loadImage("./res/grayscaleMask_mask.png");
        grayscaleMask(image.clone(), image, mask);
        MarvinImageIO.saveImage(image, "./res/grayscaleMask_output.png");
    }

    private void grayscaleMask(MarvinImage image, MarvinImage imageOut, MarvinImage mask){
        int r1,r2,g1,g2,b1,b2;
        double maskGray, factorMask, factorImage;
        for(int y=0; y<image.getHeight(); y++){
            for(int x=0; x<image.getWidth(); x++){
                r1 = image.getIntComponent0(x, y);
                g1 = image.getIntComponent1(x, y);
                b1 = image.getIntComponent2(x, y);
                r2 = mask.getIntComponent0(x, y);
                g2 = mask.getIntComponent1(x, y);
                b2 = mask.getIntComponent2(x, y);
                maskGray = (r2*0.21)+(g2*0.72)+(b2*0.07);
                factorMask = 1-(maskGray/255);
                factorImage = 1-factorMask;
                imageOut.setIntColor(x, y,  (int)(r1*factorImage+r2*factorMask),
                                            (int)(g1*factorImage+g2*factorMask),
                                            (int)(b1*factorImage+b2*factorMask));

            }
        }
    }

    public static void main(String[] args) {
        new GrayScaleMask(); System.exit(0);
    }
}

OUTPUT 2:

You can darken the mask just before combining it:

    r2 = (int)(r2*0.3);
    g2 = (int)(g2*0.3);
    b2 = (int)(b2*0.3);
    imageOut.setIntColor(x, y,  (int)((r1*factorImage+r2*factorMask)),
                                (int)((g1*factorImage+g2*factorMask)),
                                (int)((b1*factorImage+b2*factorMask)));

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM