Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java colour detection

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.

like image 592
user2517280 Avatar asked Mar 04 '14 17:03

user2517280


1 Answers

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.

like image 77
Marco13 Avatar answered Oct 14 '22 05:10

Marco13