1

I know there are similar questions to this but those ones don't answer my question. As the title reads, I am using JavaFX Image class, not bufferedImage.

I used the answer to this other question, but the resulting image is empty.

This is my code:

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;
}

can anyone tell me what the problem is.

Community
  • 1
  • 1
blaze
  • 139
  • 1
  • 3
  • 13
  • Seems like a duplicate of [How to change color of image in JavaFX](http://stackoverflow.com/questions/18124364/how-to-change-color-of-image-in-javafx)? – jewelsea Mar 30 '16 at 16:42
  • 1
    You're missing a bracket to close your inner for loop. – ManoDestra Mar 30 '16 at 16:44
  • @jewelsea, thanks, but that is not what I want. – blaze Mar 30 '16 at 16:50
  • @ManoDestra, that was my mistake. On my original source code, all the brackets are closed. – blaze Mar 30 '16 at 16:52
  • You sure you need to divide by 3 in the `int grayLevel = (int) (0.2162 * red + 0.7152 * green + 0.0722 * blue) / 3;`? Seems to me you get something around `0xff / 3` if `red = green = blue = 0xff` – fabian Mar 30 '16 at 17:32
  • @jewlsea, the main objective of my project is to read a car plate number. So, I need to convert the plate number to grayscale, in other to do character extraction and character matching on the resulting image. – blaze Mar 30 '16 at 17:38
  • hello, fabian, i have change the code to this `int grayLevel = (int) (red + green + blue) / 3` but it still doesn't work. Please inform me if there are any alternatives. Thanks – blaze Mar 30 '16 at 17:51
  • Maybe you would like to study how this [sudoku grabber](http://ladstatt.blogspot.com/2013/07/sudoku-solver-with-scala-javafx-and.html) reads printed sudoku board images and resolves characters from them. – jewelsea Mar 30 '16 at 19:25

3 Answers3

6

Update, this answer is still valid, it gives a black and white monochrome image that is a good approximation of a grayscale image, BUT it is not exactly the same as a grayscale function applied on the image. To see the difference, see the example images in this question:

ColorAdjust works on adjusting Hue, Saturation, Brightness (HSB) values, not Red, Green Blue (RGB) values. A typical grayscale algorithm multiplies the RGB values by specific constants to generate the grayscale image.

Therefore, if you need or want a true grayscale image, perform the pixel manipulations outlined in other answers instead of the ColorAdjust effect suggestion in this answer.


To get a grayscale from an image, I'd just apply a desaturation effect.

grayscale

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);
    }
}
jewelsea
  • 150,031
  • 14
  • 366
  • 406
2

I got your code working by doing the following, but I haven't entirely figured out WHY this has to be the case. It's something to do with the value of the int required for storage in the Image. You need to invert the gray level value and store the -gray integer. Maybe a Little/Big Endian issue. May be safer using a 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.
        }
    }
ManoDestra
  • 6,325
  • 6
  • 26
  • 50
1

It works if alpha is also taken into account, and the weighted sum is not divided by 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;
}
drsl
  • 11
  • 1