0

I'm looking to use a very crude heightmap I've created in Photoshop to define a tiled isometric grid for me:

Map: https://i.stack.imgur.com/I4EFu.png

I'm aiming to loop through every pixel in the image and convert the colour of that pixel to a scale of my choosing, for example 0-100.

At the moment I'm using the following code:

    try
    {
        final File file = new File("D:\\clouds.png");
        final BufferedImage image = ImageIO.read(file);

        for (int x = 0; x < image.getWidth(); x++) 
        {
            for (int y = 0; y < image.getHeight(); y++) 
            {
                int clr = image.getRGB(x, y) / 99999;
                if (clr <= 0)
                    clr = -clr;

                System.out.println(clr);        
            }
        }
    }
    catch (IOException ex)
    {
         // Deal with exception
    }

This works to an extent; the black pixel at position 0 is 167 and the white pixel at position 999 is 0. However when I insert certain pixels into the image I get slightly odd results, for example a gray pixel that's very close to white returns over 100 when I would expect it to be in single digits.

Is there an alternate solution I could use that would yield more reliable results?

Many thanks.

BeepBeep
  • 151
  • 3
  • 9

2 Answers2

1

getRGB returns all channels packed into one int so you shouldn't do arithmetic with it. Maybe use the norm of the RGB-vector instead?

for (int x = 0; x < image.getWidth(); ++x) {
    for (int y = 0; y < image.getHeight(); ++y) {
        final int rgb = image.getRGB(x, y);
        final int red   = ((rgb & 0xFF0000) >> 16);
        final int green = ((rgb & 0x00FF00) >>  8);
        final int blue  = ((rgb & 0x0000FF) >>  0);
        // Norm of RGB vector mapped to the unit interval.
        final double intensity =
            Math.sqrt(red * red + green * green + blue * blue)
            / Math.sqrt(3 * 255 * 255);
    }
}

Note that there is also the java.awt.Color class that can be instantiated with the int returned by getRGB and provides getRed, getGreen and getBlue methods if you don't want to do the bit manipulations yourself.

5gon12eder
  • 24,280
  • 5
  • 45
  • 92
  • Thanks. Could you explain in laymans terms what the above code is doing? (specifically the lines with the bitwise operations) Also your code produces a range from 0.4 to 1, how can I adapt it to change the range? Cheers. – BeepBeep Sep 17 '14 at 00:44
  • They extract the red, green and blue parts. See my update mentioning `java.awt.Color`. You'll probably feel safer with it. As pointed out by another answer, if your image is *always* grayscale, the three channels will always be the same so you could chose only one of them. – 5gon12eder Sep 17 '14 at 00:45
  • Ah I see, thanks for the explanation. I've accepted the other answer because it's simpler and more understandable for me personally. I don't understand the vector norm part well enough to be comfortable using it. – BeepBeep Sep 17 '14 at 00:52
1

Since it's a grayscale map, the RGB parts will all be the same value (with range 0 - 255), so just take one out of the packed integer and find out what percent of 255 it is:

int clr = (int) ((image.getRGB(x, y) & 0xFF) / 255.0 * 100);

System.out.println(clr);        
Matt Eckert
  • 1,946
  • 14
  • 16