0

I have tried to grayscale a already black-white-gray picture and it become black.

When I try to grayscale a picture with Java, I do like this:

    // This turns the image data to grayscale and return the data
    private static RealMatrix imageData(File picture) {
        try {
            BufferedImage image = ImageIO.read(picture);
            int width = image.getWidth();
            int height = image.getHeight();
            RealMatrix data = MatrixUtils.createRealMatrix(height * width, 1);
            // Convert to grayscale
            int countRows = 0;
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    // Turn image to grayscale
                    int p = image.getRGB(x, y);
                    int r = (p >> 16) & 0xff;
                    int g = (p >> 8) & 0xff;
                    int b = p & 0xff;

                    // calculate average and save
                    int avg = (r + g + b) / 3;
                    data.setEntry(countRows, 0, avg);
                    countRows++;
                }
            }
            return data;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

The problem what I see is that p is an 32-bit value and I only want 8-bit value. Even if the picture is already grayscaled, the p value is already a 32-bit value. That cause trouble for me.

So if I grayscale a gray picture, it will become black. Or at least darker. And I want 0..255 values of p, which is a 32-bit integer value.

Do you have any suggestions how to read pictures as they where 8-bit? It's for image classification.

Summarize:

I need help to get each pixels from a picture in 0..255 format. One way is to gray scale it, but how can I verify if the picture is already gray scaled?

Update:

I have tried to read a picture as it was 8-bit values. It works. Then I try to save the picture with the same values. The picture becomes very dark.

I have a matlab example I want to show. First I read my picture:

image = imread("subject01.normal");

enter image description here

And then I save the picture.

imwrite(uint8(image), "theSameImage.gif")

enter image description here

If I try with a minimal Java code snipped for reading an image.

private static void imageData(File picture) {
        try {
            BufferedImage image = ImageIO.read(picture);
            int width = image.getWidth();
            int height = image.getHeight();
            DataBuffer buffer = image.getRaster().getDataBuffer();
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    int p = buffer.getElem(x + y * width);
                    image.setRGB(x, y, p);
                }
            }
            File output = new File(picture.getName());
            ImageIO.write(image, "gif", output);
            return data;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

I will get this picture:

enter image description here

So even if there is a marked answer in this question, it's still not going to help you.

euraad
  • 2,467
  • 5
  • 30
  • 51
  • 1
    `addToEntry(countRows, 0, avg)`?? Did you perhaps mean `addToEntry(y, x, avg)`? – Andreas May 14 '20 at 15:36
  • @Andreas No sorry. I'm using Apache Common Math library to save the 0..255 values into a column matrix. – euraad May 14 '20 at 15:37
  • Matrix starts out with all cells having a value of 0 (black). [`addToEntry(int row, int column, double increment)`](http://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/org/apache/commons/math3/linear/RealMatrix.html#addToEntry(int,%20int,%20double)) will increment the value of the given cell. Since you call it with `column = 0` for all pixels in a given image row, the **first cell** ends up with some value after overflowing many times, and all the rest of the cells in that row stay 0 (black). – Andreas May 14 '20 at 15:41
  • The average of R, G, and B is incorrect. Human vision is more sensitive to green light, and less sensitive to red. The values should be weighed accordingly. See https://stackoverflow.com/questions/687261/converting-rgb-to-grayscale-intensity – David Conrad May 14 '20 at 15:41
  • @Andreas I want a column matrix. Long vector in other words. – euraad May 14 '20 at 15:42
  • 1
    @DanielMårtensson Then perhaps you should **edit** the question and **clarify** that, because I'm obviously not the only one that missed the part where the matrix is a vector. – Andreas May 14 '20 at 15:45
  • @Andreas I changed `addToEntry` to `setEntry`. Which is correct way, but does not change the data at all because `data` is already a zero vector. I have issues with to get 0..255 values from the `image` object. That's because `getRGB` return an `int` value of 32 bit. – euraad May 14 '20 at 15:49
  • Since the matrix values are `double` values, are they perhaps supposed to be 0.0 - 1.0, not 0 - 255? We cannot see how you're using the matrix, so there's no way for us to know what range the values are supposed to be. --- Changing `addToEntry` to `setEntry` does not clarify that "matrix" is a "vector". – Andreas May 14 '20 at 15:49
  • @Andreas In this case, they can be `0.0..255.0`. But when I read a pixle, I get like `23241` and `23551` values from `p`. – euraad May 14 '20 at 15:51
  • `23241` is `#005AC9`, aka [Navy Blue](https://www.htmlcsscolor.com/hex/005AC9). – Andreas May 14 '20 at 15:53
  • 1
    @DanielMårtensson I just tested your code and it's working just fine for me. I put a test image through the method and the resulting `RealMatrx` contains values between 0 and 255. I've also wrote the resulting `avg` back into the image and saved that, and the result is a black and white version of the original image. – Marv May 14 '20 at 15:55
  • @Andreas Yes. I also get `-1` and `-6908266` – euraad May 14 '20 at 15:56
  • @Marv What numbers do you get if you read a gray picture? – euraad May 14 '20 at 15:57
  • @DanielMårtensson these are perfectly fine values for an RGB value. Try printing `-1` (#FFFFFF) and `-6908266` (#969696) in hexadecimal. – Marv May 14 '20 at 15:58
  • @Marv Mine pictures becomes very dark if I try to save `image.setRGB(x, y, avg)` and save the object `image`. – euraad May 14 '20 at 15:59
  • It is weird that you would get `23241` aka **Navy Blue** from an image that is supposedly already grayscale. – Andreas May 14 '20 at 16:00
  • @DanielMårtensson You would need to save it as `image.setRGB(x, y, new Color(avg, avg, avg).getRGB())`, since `avg` is a value between 0 and 255, not an rgb value, but `BufferedImage.setRGB` expects an RGB value. – Marv May 14 '20 at 16:00
  • @Marv Hmm. Thanks. But the `avg` value is that I want to use, but they are to dark. My pictures are already gray, so I assume that they are 8-bit pixles? – euraad May 14 '20 at 16:08
  • @Marv Here. use this database http://vision.ucsd.edu/content/yale-face-database – euraad May 14 '20 at 16:09
  • @DanielMårtensson It works for me. – Marv May 14 '20 at 16:11
  • @Andreas Thanks. That is a good answer! – euraad May 14 '20 at 16:25
  • **Unable to reproduce!** The images shown in the question are not consistent with the claim that `getRGB()` returns values like `23241` and `23551`. All the values returned are like `0xff3a3a3a`, which is a gray color with alpha 100%. As such, your code should have worked perfectly. – Andreas May 14 '20 at 17:51
  • @Andreas But when I try to save it, even with the old code. I get a dark image. I don't want that. – euraad May 14 '20 at 17:55
  • @DanielMårtensson Maybe it's the code that *uses* the returned matrix (vector) that's in error, but we can't see that code, so how would we know what it actually does. – Andreas May 14 '20 at 17:57
  • @Andreas No. No vector here. I have removed it. I'm only reading the picture and save its pixel values as a new picture. – euraad May 14 '20 at 18:06
  • @DanielMårtensson So you totally changed the question to entirely different code? Next time, create a *new* question. – Andreas May 14 '20 at 20:32
  • @Andreas Some people suggest the reverse - extending and elobaerate the question. – euraad May 14 '20 at 22:20

1 Answers1

1

You mentioned that the image you're reading is a grayscale image, and that getRGB returns values like 23241 and 23551.

That means your image uses a CS_GRAY ColorSpace, not an RGB color space. You can confirm this by calling getType(), which would return TYPE_USHORT_GRAY.

That means that your p value is a gray-level in range 0 - 65535. Since you want the result to be a double in range 0 - 255, you need to calculate:

double avg = p * 255.0 / 65535.0;

Unless you're 100% sure the input image will always be grayscale, you should check the type in the code and handle the p value accordingly.

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Curious, because when I use OPs images and his code, it works for me. He also gets values like `-1` and `-6908266`, which are `#FFFFFF` and `#969696` respectively in RGB space. – Marv May 14 '20 at 16:13
  • @Marv See [duplicate answer](https://stackoverflow.com/a/26095941/5221149), which mentions the `-1` problem. – Andreas May 14 '20 at 16:16
  • Very good, but I get negative values because my `p` is negative. And `p` values are not 8-bit at all. – euraad May 14 '20 at 16:17
  • Here all. this MATLAB code shoots out 0..255 https://github.com/bytefish/facerec/blob/ddce12a933cfcf517ec3a352f5151348799f414a/m/util/read_images.m#L44 – euraad May 14 '20 at 16:18
  • @Andreas Sorry. But cannot cast `DataBuffer` to `DataBufferUShort` – euraad May 14 '20 at 16:39
  • @DanielMårtensson Why not? What exception do you get? – Andreas May 14 '20 at 17:21
  • @Andreas Cannot cast exception. I'm going to rewrite the question with a MATLAB snippet. Can you open it after that? – euraad May 14 '20 at 17:25
  • @DanielMårtensson Can you show the ***exact*** and ***complete*** error message, i.e. include all the *relevant* information? – Andreas May 14 '20 at 17:26
  • `java.lang.ClassCastException: class java.awt.image.DataBufferByte cannot be cast to class java.awt.image.DataBufferUShort (java.awt.image.DataBufferByte and java.awt.image.DataBufferUShort are in module java.desktop of loader 'bootstrap') ` – euraad May 14 '20 at 17:32
  • @DanielMårtensson So you **didn't** follow my recommendation to call `getType()` to verify that return value would be `TYPE_USHORT_GRAY`. I bet, if you actually did that, you'd get `TYPE_BYTE_GRAY` instead, which is why you get a `DataBufferByte`, not a `DataBufferUShort`. That would seem *logical*, don't you agree? – Andreas May 14 '20 at 17:35
  • Yes. I did that and I could verify that `BufferedImage.TYPE_BYTE_GRAY` was not `getType()` in this case. – euraad May 14 '20 at 17:38
  • It was `TYPE_BYTE_INDEXED` – euraad May 14 '20 at 17:39