6

Im looking to implement a feature in Java which reads an image and is able to detect where there are shades of red, blue, green, yellow, etc. as part of a satellite image analysis program. So for example in a standard satellite image, blue would be water so I would like the program to read how many pixels are blue and then it could say x% of the image is water.

I know it would be possible using a whole load of logic statements by reading the RGB value of each pixel but is there an easier way to do this? Otherwise there will be hundreds of if statements which is going to take a long time to write but also a long time to perform. Ideally id like something like this:

if (pixelValue = red) {
   redCounter++;
}

Which is obviously very simple but it would save having to go through every single possible RGB combination for red, blue, green, yellow, purple, etc. which are all colours present in some of the coloured images.

Thanks in advance.

user2517280
  • 221
  • 1
  • 5
  • 14
  • Maybe this can help: http://stackoverflow.com/questions/6524196/java-get-pixel-array-from-image – Frakcool Mar 04 '14 at 17:38
  • I know how to use `getRGB`, `getRed`, etc. for each pixel as I use this in one of the algorithms but id then have to define the `red` variable as every possible RGB combination of red? – user2517280 Mar 04 '14 at 17:50

1 Answers1

23

You have to read every pixel anyhow. You can do this with

int rgb = bufferedImage.getRGB(x,y);

Alternatively, you can obtain the data buffer from the image and directly obtain the pixels as an int[] array (as described in the comments), but note that this may have some impact on the performance when rendering this image afterwards.

The next step would be to detect whether the pixel has a certain color. When it comes to photos, a comparison like

if (rgb == Color.BLUE.getRGB()) { ... }

does not make sense: The pixels will not be perfectly blue in most cases. Instead, you could analyze the hue of the RGB value, by converting it into the HSB color space. So you could do something like

float hsb[] = new float[3];
int r = (rgb >> 16) & 0xFF;
int g = (rgb >>  8) & 0xFF;
int b = (rgb      ) & 0xFF;
Color.RGBtoHSB(r, g, b, hsb);

Then the hsb array will contain the hue, saturation and brightness of the color. These will be values between 0 and 1. The hue multiplied with 360 will give you the "tone" of the color:

HSV

The saturation and brightness can be used to detect pixels that are "nearly black" or "nearly white". So your final analysis could roughly (!) look like this:

if      (hsb[1] < 0.1 && hsb[2] > 0.9) nearlyWhite();
else if (hsb[2] < 0.1) nearlyBlack();
else {
    float deg = hsb[0]*360;
    if      (deg >=   0 && deg <  30) red();
    else if (deg >=  30 && deg <  90) yellow();
    else if (deg >=  90 && deg < 150) green();
    else if (deg >= 150 && deg < 210) cyan();
    else if (deg >= 210 && deg < 270) blue();
    else if (deg >= 270 && deg < 330) magenta();
    else red();
}

These nested if-statements could also be avoided by using a NavigableMap and its floorEntry and ceilingEntry methods, but the if-statements are probably easier to understand here.

Marco13
  • 53,703
  • 9
  • 80
  • 159
  • This is great, thank you. I was just looking into HSB as I wasn't sure how it was read in Java as it gives values between 0 and 1 where as its supposed to be between 0 and 360 but obviously you've explained that and more so thanks a lot. – user2517280 Mar 04 '14 at 18:27
  • what's the degree for deciding orange value? – Jay Dangar Apr 27 '18 at 09:59
  • 1
    @JayDangar That solely depends on which color you want to consider as "orange". For example, would you consider [this color](http://html-color.org/FFCC00) as "orange" or as "yellow"? However, using something like `(deg >= 30 && deg < 45)` for `orange()` could be ok... – Marco13 Apr 27 '18 at 11:15
  • Well, your algorithm works really great, but in certain scenarios like outdoor coditions brightness is high, so there is high chances that we got wrong output, in most of the time the detected color would be white. Can you tell me any other methods by which I can solve this kind of more brightness issues?? – Jay Dangar May 15 '18 at 02:33
  • @JayDangar Similar to the question about "orange": You can adjust the limits as you wish. Right now, "white" is determined by `hsb[2] > 0.9`, and you can change this to `hsb[2] > 0.95`, **but** maybe I should emphasize: The answer here shows a very basic approach for a "pixel color classification". In a real-world application, one could consider more sophisticated approaches for computing the "color name" from the hue. You should also consider *preprocessing* the image, for example, in order to maximize the contrast (e.g. based on the [histogram](https://photo.stackexchange.com/q/450) ) – Marco13 May 15 '18 at 02:45
  • @Marco13, thanks man for the efforts... I will look through the histogram based approach, appreciated your help. – Jay Dangar May 15 '18 at 05:26