Create an image-overlay mask in javafx

前端 未结 1 1267
无人及你
无人及你 2021-01-06 23:23

I\'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 re

相关标签:
1条回答
  • 2021-01-06 23:59

    What you are Doing Wrong

    The difference operator isn't a binary difference based on whether a pixel is set instead it is a difference in the RGB components, so instead of a solid red overlay, you will get a multi-colored overlay because the difference in the RGB components of the blended images differs between pixels.

    Background

    You are trying to do something similar to a masked bit-blit operation with blend modes (basically, an OR then an AND of pixel data based on a white on black mask). It is possible though a little tricky with the built-in blends in JavaFX 8.

    You could create a feature request for additional support in the blend API for bit-blt style basics as well as exposing a full porter duff compositing implementation like Swing has so that the underlying blend engine has a bit more power and is possibly a little easier to use.

    Alternatives

    The preferred thing to do would be to pre-process your mask in an image editor like photoshop to convert the black part to an alpha channel - then you can just layer your mask on top of your original and the default compositing mode will take of it.

    To make your alpha enabled mask red, you could just use mask.setBlendMode(BlendMode.RED) (or you could pre-color the mask in an image editor before using it in your program).

    Another alternative is the PixelReader solution you have in your question (which I think is fine if you are unable to pre-convert your mask to use alpha).

    The blend operations can be hardware accelerated on appropriate hardware. So potentially using a blend could be faster if you are doing it very often (but you would have to have many blends being run very quickly on large images to really notice any kind of performance difference).

    Sample Solution Using Blend Operations

    Sample Output

    blended

    Input Images

    original.jpg

    original

    stencil.jpg

    stencil

    Code

    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();
        }
    }
    
    0 讨论(0)
提交回复
热议问题