首页 文章

在javafx中创建图像叠加蒙版

提问于
浏览
2

我'm trying to do a simple thing. I have a binary image and all I want is to overlay the binary image on a color image, but the white pixels in the binary image should be red, and the black transparent. I'我很习惯JavaFx但是我确信有一种更简单的方法 . 我尝试使用某种混合效果但到目前为止没有运气 . 我认为它应该类似于:How to Blend two Image in javaFX

Example of what I want to achieve

我想出了这个:Image image = new Image(“/ circle.jpg”,false); ImageView iv = new ImageView(image);

Image mask = new Image("/mask.jpg", false);
ImageView ivMask = new ImageView(mask);

Rectangle r = new Rectangle(mask.getWidth(), mask.getHeight());
r.setFill(Color.RED);

r.setBlendMode(BlendMode.MULTIPLY); // sets the white area red

Group g = new Group(ivMask, r);   // sets the white area red


// this is not working as expected
iv.setBlendMode(BlendMode.DIFFERENCE);

Group g2 = new Group(iv, g);

谢谢你的任何建议!如果您认为,按像素处理比仅创建叠加更快,请告诉我 .

像素阅读器的解决方案是:

Pane root = new Pane();

// read the underlaying image
root.getChildren().add(new ImageView(new Image("/src.jpg")));

Image mask = new Image("/mask.jpg");
PixelReader pixelReader = mask.getPixelReader();

Canvas resultCanvas = new Canvas();
root.getChildren().add(resultCanvas);

GraphicsContext resultLayer = resultCanvas.getGraphicsContext2D();
for (int y = 0; y < mask.getHeight(); y++) {
  for (int x = 0; x < mask.getWidth(); x++) {
    if( pixelReader.getColor(x, y).equals(Color.WHITE) ){
      resultLayer.fillRect(x, y, 1.0, 1.0);
    }
  }
}

干杯!

1 回答

  • 3

    What you are Doing Wrong

    差异运算符不是基于是否设置像素而不是RGB分量的差异的二进制差异,因此代替实心红色叠加,您将获得多色叠加,因为RGB组件的差异混合图像在像素之间不同 .

    Background

    您正在尝试使用混合模式执行与masked bit-blit operation类似的操作(基本上是OR,然后是基于黑色蒙版上的白色的像素数据的AND) . JavaFX 8中的内置混合可能有点棘手 .

    您可以在混合API中为bit-blt样式基础创建一个功能请求,以及公开Swing has这样的完整porter duff compositing实现,以便底层混合引擎具有更强大的功能,并且可能更容易使用 .

    Alternatives

    首选的方法是在像photoshop这样的图像编辑器中预处理你的蒙版,将黑色部分转换为alpha通道 - 然后你可以将你的蒙版层叠在原始图像上,默认的合成模式将采用它 .

    要使支持alpha的蒙版成为红色,您可以使用 mask.setBlendMode(BlendMode.RED) (或者您可以在图像编辑器中对蒙版进行预着色,然后再在程序中使用它) .

    另一种选择是您在问题中使用的PixelReader解决方案(如果您无法预先将掩码转换为使用alpha,我认为这很好) .

    混合操作可以在适当的硬件上进行硬件加速 . 因此,如果您经常使用混合可能会更快(但是您必须在大图像上快速运行许多混合才能真正注意到任何类型的性能差异) .

    Sample Solution Using Blend Operations

    样本输出

    blended

    输入图像

    original.jpg

    original

    stencil.jpg

    stencil

    import javafx.application.Application;
    import javafx.geometry.Insets;
    import javafx.scene.*;
    import javafx.scene.effect.BlendMode;
    import javafx.scene.image.*;
    import javafx.scene.layout.HBox;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Rectangle;
    import javafx.stage.Stage;
    
    public class Blended extends Application {
        @Override
        public void start(Stage stage) {
            Image original = new Image(
                getClass().getResourceAsStream("original.jpg")
            );
    
            Image stencil = new Image(
                getClass().getResourceAsStream("stencil.jpg")
            );
    
            // first invert the stencil so that it is black on white rather than white on black.
            Rectangle whiteRect = new Rectangle(stencil.getWidth(), stencil.getHeight());
            whiteRect.setFill(Color.WHITE);
            whiteRect.setBlendMode(BlendMode.DIFFERENCE);
    
            Group inverted = new Group(
                    new ImageView(stencil),
                    whiteRect
            );
    
            // overlay the black portions of the inverted mask onto the image.
            inverted.setBlendMode(BlendMode.MULTIPLY);
            Group overlaidBlack = new Group(
                    new ImageView(original),
                    inverted
            );
    
            // create a new mask with a red tint (red on black).
            Rectangle redRect = new Rectangle(stencil.getWidth(), stencil.getHeight());
            redRect.setFill(Color.RED);
            redRect.setBlendMode(BlendMode.MULTIPLY);
    
            Group redStencil = new Group(
                    new ImageView(stencil),
                    redRect
            );
    
            // overlay the red mask on to the image.
            redStencil.setBlendMode(BlendMode.ADD);
            Group overlaidRed = new Group(
                    overlaidBlack,
                    redStencil
            );
    
            // display the original, composite image and stencil.
            HBox layout = new HBox(10);
            layout.getChildren().addAll(
                    new ImageView(original),
                    overlaidRed,
                    new ImageView(stencil)
            );
            layout.setPadding(new Insets(10));
            stage.setScene(new Scene(layout));
            stage.show();
        }
    
        public static void main(String[] args) {
            launch();
        }
    }
    

相关问题