javafx argb 到灰度转换

javafx argb to grayscale conversion

我知道有类似的问题,但那些没有回答我的问题。如标题所示,我使用的是 JavaFX Image class,而不是 bufferedImage。

我使用了 this 其他问题的答案,但生成的图像是空的。

这是我的代码:

public static Image toGrayScale(Image sourceImage) {
    PixelReader pixelReader = sourceImage.getPixelReader();

    int width = (int) sourceImage.getWidth();
    int height = (int) sourceImage.getHeight();

    WritableImage grayImage = new WritableImage(width, height);

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            int pixel = pixelReader.getArgb(x, y);

            int red = ((pixel >> 16) & 0xff);
            int green = ((pixel >> 8) & 0xff);
            int blue = (pixel & 0xff);

            int grayLevel = (int) (0.2162 * red + 0.7152 * green + 0.0722 * blue) / 3;
            int gray = (grayLevel << 16) + (grayLevel << 8) + grayLevel;

            grayImage.getPixelWriter().setArgb(x, y, gray);

    }
    return grayImage;
}

谁能告诉我问题出在哪里。

我通过执行以下操作让您的代码正常工作,但我还没有完全弄清楚为什么一定要这样。与Image中存储所需的int值有关。您需要反转灰度值并存储 -gray 整数。可能是 Little/Big Endian 问题。使用 ColorAdjust.

可能更安全
    // Put this outside the loops
    // so we have easier access to the writer.
    PixelWriter pixelWriter = grayImage.getPixelWriter(); 
    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
            int pixel = pixelReader.getArgb(x, y);

            int red = ((pixel >> 16) & 0xff);
            int green = ((pixel >> 8) & 0xff);
            int blue = (pixel & 0xff);

            int grayLevel = (int) (0.2162 * (double)red + 0.7152 * (double)green + 0.0722 * (double)blue) / 3;
            grayLevel = 255 - grayLevel; // Inverted the grayLevel value here.
            int gray = (grayLevel << 16) + (grayLevel << 8) + grayLevel;

            pixelWriter.setArgb(x, y, -gray); // AMENDED TO -gray here.
        }
    }

更新,这个答案仍然有效,它给出的黑白单色图像非常接近灰度图像,但是它与灰度图像不完全相同应用于图像的灰度函数。要查看差异,请查看此问题中的示例图像:

  • Desaturation effect washes away contrast

ColorAdjust 用于调整色调、饱和度、亮度 (HSB) 值,而不是红色、绿色蓝色 (RGB) 值。典型的 grayscale algorithm 将 RGB 值乘以特定常数来生成灰度图像。

因此,如果您需要或想要真正的灰度图像,请执行其他答案中概述的像素操作,而不是此答案中的 ColorAdjust 效果建议。


要从图像中获取灰度,我只需应用 desaturation effect

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.*;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class Desaturation extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Image image = new Image(
                "http://www.iamqurat.com/wp-content/uploads/2016/02/National_Flower_Rose_flickr_20140901.jpg",
                200,
                0,
                true,
                true
        );

        ImageView original = new ImageView(image);

        ImageView desaturated = new ImageView(image);
        ColorAdjust desaturate = new ColorAdjust();
        desaturate.setSaturation(-1);
        desaturated.setEffect(desaturate);

        Scene scene = new Scene(new HBox(original, desaturated));
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

如果也考虑了alpha,并且加权和不除以3就有效:

public static Image toGrayScale(Image sourceImage) {
    PixelReader pixelReader = sourceImage.getPixelReader();

    int width = (int) sourceImage.getWidth();
    int height = (int) sourceImage.getHeight();

    WritableImage grayImage = new WritableImage(width, height);

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            int pixel = pixelReader.getArgb(x, y);

            int alpha = ((pixel >> 24) & 0xff);
            int red = ((pixel >> 16) & 0xff);
            int green = ((pixel >> 8) & 0xff);
            int blue = (pixel & 0xff);

            int grayLevel = (int) (0.2162 * red + 0.7152 * green + 0.0722 * blue);
            int gray = (alpha << 24) + (grayLevel << 16) + (grayLevel << 8) + grayLevel;

            grayImage.getPixelWriter().setArgb(x, y, gray);
        }           
    }
    return grayImage;
}