代码之家  ›  专栏  ›  技术社区  ›  blaster

在javafx中创建图像覆盖掩码

  •  4
  • blaster  · 技术社区  · 10 年前

    我想做一件简单的事。我有一个二进制图像,我只想将二进制图像覆盖在彩色图像上,但是二进制图像中的白色像素应该是红色的,黑色是透明的。 我很习惯JavaFx,但我一直坚持这个。我知道我可以通过PixelReader遍历所有像素来实现这一点,但我相信有一种更简单的方法。我试图使用某种混合效果,但迄今为止没有成功。 我认为应该与此类似: How to Blend two Image in javaFX

    Example of what I want to achieve

    我想到了这个: Image Image=新图像(“/circule.jpg”,false); ImageView iv=新ImageView(图像);

    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 回复  |  直到 8 年前
        1
  •  5
  •   jewelsea    10 年前

    你做错了什么

    差异运算符不是基于像素是否设置的二进制差异,而是RGB成分的差异,因此,您将获得多色覆盖,而不是纯红色覆盖,因为混合图像的RGB成分差异在像素之间不同。

    出身背景

    您正在尝试做类似于 masked bit-blit operation 混合模式(基本上是基于黑上白掩模的像素数据的OR和AND)。这是可能的,尽管在JavaFX8中内置的混合有点棘手。

    您可以在混合API中创建一个功能请求,以获得对bit blt风格基础知识的额外支持,并公开一个完整的 porter duff compositing 类似于实现 Swing has 因此,基础混合引擎具有更大的功率,并且可能更易于使用。

    选择

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

    要使启用alpha的遮罩变为红色,可以使用 mask.setBlendMode(BlendMode.RED) (或者,您可以在程序中使用遮罩之前,在图像编辑器中预先为遮罩上色)。

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

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

    使用混合操作的样本溶液

    样本输出

    blended

    输入图像

    原始.jpg

    original

    模板.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();
        }
    }