5

I have following code, which creates grayscale BufferedImage and then sets random colors of each pixel.

import java.awt.image.BufferedImage;

public class Main {

    public static void main(String[] args) {
        BufferedImage right = new BufferedImage(100, 100, BufferedImage.TYPE_BYTE_GRAY);
        int correct = 0, error = 0;
        for (int i = 0; i < right.getWidth(); i++) {
            for (int j = 0; j < right.getHeight(); j++) {
                int average = (int) (Math.random() * 255);
                int color = (0xff << 24) | (average << 16) | (average << 8) | average;
                right.setRGB(i, j, color);
                if(color != right.getRGB(i, j)) {
                    error++;
                } else {
                    correct++;
                }
            }
        }
        System.out.println(correct + ", " + error);
    }
}

In approximately 25-30% pixels occurs weird behaviour, where I set color and right afterwards it has different value than was previously set. Am I setting colors the wrong way?

Glissinda
  • 169
  • 1
  • 9

3 Answers3

2

Here is your solution: ban getRGB and use the Raster (faster and easier than getRGB) or even better DataBuffer (fastest but you have to handle the encoding):

import java.awt.image.BufferedImage;

public class Main
{

public static void main(String[] args)
    {
    BufferedImage right = new BufferedImage(100, 100, BufferedImage.TYPE_BYTE_GRAY);
    int correct = 0, error = 0;
    for (int x=0 ; x < right.getWidth(); x++)
        for (int j = 0; j < right.getHeight(); j++)
            {
            int average = (int) (Math.random() * 255) ;
            right.getRaster().setSample(x, y, 0, average) ;
            if ( average != right.getRaster().getSample(x, y, 0) ) error++ ;
            else correct++;
            }
    System.out.println(correct + ", " + error);
    }
}

In your case getRGB is terrible, because the encoding is an array of byte (8 bits), and you have to manipulate RGB values with getRGB. The raster does all the work of conversion for you.

FiReTiTi
  • 5,597
  • 12
  • 30
  • 58
1

I think your issue has to do with the image type (third parameter for BufferedImage constructor). If you change the type to BufferedImage.TYPE_INT_ARGB, then you will get 100% correct results.

Looking at the documentation for BufferedImage.getRGB(int,int) there is some conversion when you get RGB that is not the default color space

Returns an integer pixel in the default RGB color model (TYPE_INT_ARGB) and default sRGB colorspace. Color conversion takes place if this default model does not match the image ColorModel.

So you're probably seeing the mismatches due to the conversion.

FriedSaucePots
  • 1,342
  • 10
  • 16
  • Unfortunately, I need it to be `BufferedImage.TYPE_BYTE_GRAY`. Am I not creating grayscale color with this line: `int color = (0xff << 24) | (average << 16) | (average << 8) | average;` ? Thanks for help – Glissinda May 17 '16 at 16:17
  • Ya I didn't mean to imply that you should change your color model, just that the color model is introducing some conversion causing your issue. The current color you're making is in the ARGB model so you'll need to figure out the grayscale model color format and make colors that way. – FriedSaucePots May 17 '16 at 16:48
0

Wild guess:

Remove (0xff << 24) | which is the alpha channel, how intransparent/opaque the color is. Given yes/no transparent and average < or >= 128 application of transparency, 25% could be the wrong color mapping (very wild guess).

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • Not sure, if removing `(0xff << 24) |` really solves the problem. The mistake seems to be in significant bit, not the alpha channel. – Glissinda May 17 '16 at 17:13
  • Sorry, I am no help there, try `int average = (int) (Math.random() * 127);` or `average | 0xff_00_00:_00`. Sign extension cannot have happened. – Joop Eggen May 17 '16 at 17:28