Find color name if it has Hue in android

I only have 12 colors:

red: RGB: 255, 0, 0
pink: RGB: 255, 192, 203
violet: RGB: 36, 10, 64
blue: RGB: 0, 0, 255
green: RGB: 0, 255, 0
yellow: RGB: 255, 255, 0
orange: RGB: 255, 104, 31
white: RGB: 255, 255, 255
black: RGB: 0, 0, 0
gray: RGB: 128, 128, 128
tea: RGB: 193, 186, 176
cream: RGB: 255, 253, 208

      

When I read the pixel of the bitmap, I can get the hue value:

int picw = mBitmap.getWidth();
    int pich = mBitmap.getHeight();
    int[] pix = new int[picw * pich];
    float[] HSV = new float[3];

    // get pixel array from source
    mBitmap.getPixels(pix, 0, picw, 0, 0, picw, pich);

    int index = 0;
    // iteration through pixels
    for(int y = 0; y < pich; ++y) {
        for(int x = 0; x < picw; ++x) {
            // get current index in 2D-matrix
            index = y * picw + x;               
            // convert to HSV
            Color.colorToHSV(pix[index], HSV);
            // increase Saturation level
            //HSV[0] = Hue
            Log.i(getCallingPackage(), String.valueOf(HSV[0]));
        }
    }

      

Now I want to know what is the color of this pixel (only 12 colors above)?

I am using HSV to view a range of colors. When I have a color that is not on this list, I want to name it a similar color on my list. How can I do this?

thank you very much

+1


source to share


2 answers


Based on your comments, it seems that you are basically trying to reduce the full color bitmap palette to only the 12 you specified. Obviously, for each pixel in the bitmap, the "best fit" of the 12 should be chosen.

I still don't understand why you want the HSV values ​​as this is just a different representation of the RGB components - it doesn't actually change the problem or the solution.

A straight forward approach to finding the best match for any RGB color would look something like this.

First, create some kind of list containing the colors you want to match. I used the map since you mentioned (also) wanted to know the name of the color, not just the RGB value.

Map<String, Integer> mColors = new HashMap<String, Integer>();
mColors.put("red", Color.rgb(255, 0, 0));
mColors.put("pink", Color.rgb(255, 192, 203));
mColors.put("voilet", Color.rgb(36, 10, 64));
mColors.put("blue", Color.rgb(0, 0, 255));
mColors.put("green", Color.rgb(0, 255, 0));
mColors.put("yellow", Color.rgb(255, 255, 0));
mColors.put("orange", Color.rgb(255, 104, 31));
mColors.put("white", Color.rgb(255, 255, 255));
mColors.put("black", Color.rgb(0, 0, 0));
mColors.put("gray", Color.rgb(128, 128, 128));
mColors.put("tea", Color.rgb(193, 186, 176));
mColors.put("cream", Color.rgb(255, 253, 208));

      

Then just create a method that tells you the best match. You can call this from your second loop and pass the current pixel color to it. I have added some inline comments to explain the various steps, but this is really quite trivial.

private String getBestMatchingColorName(int pixelColor) {
    // largest difference is 255 for every colour component
    int currentDifference = 3 * 255;
    // name of the best matching colour
    String closestColorName = null;
    // get int values for all three colour components of the pixel
    int pixelColorR = Color.red(pixelColor);
    int pixelColorG = Color.green(pixelColor);
    int pixelColorB = Color.blue(pixelColor);

    Iterator<String> colorNameIterator = mColors.keySet().iterator();
    // continue iterating if the map contains a next colour and the difference is greater than zero.
    // a difference of zero means we've found an exact match, so there no point in iterating further.
    while (colorNameIterator.hasNext() && currentDifference > 0) {
        // this colour name
        String currentColorName = colorNameIterator.next();
        // this colour int value
        int color = mColors.get(currentColorName);
        // get int values for all three colour components of this colour
        int colorR = Color.red(color);
        int colorG = Color.green(color);
        int colorB = Color.blue(color); 
        // calculate sum of absolute differences that indicates how good this match is 
        int difference = Math.abs(pixelColorR - colorR) + Math.abs(pixelColorG - colorG) + Math.abs(pixelColorB - colorB);
        // a smaller difference means a better match, so keep track of it
        if (currentDifference > difference) {
            currentDifference = difference;
            closestColorName = currentColorName;
        }
    }
    return closestColorName;
}

      

Quick test results using some predefined color constants:



Color.RED (-65536) -> red (-65536)
Color.GREEN (-16711936) -> green (-16711936)
Color.BLUE (-16776961) -> blue (-16776961)
Color.BLACK (-16777216) -> black (-16777216)
Color.WHITE (-1) -> white (-1)
Color.GRAY (-7829368) -> gray (-8355712)
Color.YELLOW (-256) -> yellow (-256)
Color.MAGENTA (-65281) -> pink (-16181)

      

The first number between the parentheses is the actual int value for the color constant, the second is the int value for the best match with the name right before it.

The result for Color.MAGENTA

also illustrates why you shouldn't just compare the int color value directly. The actual value is int -65281

, which is pretty close to the value for Color.RED

(-65536). However, the best match based on different components is pink, which has a value of -16181. Obviously this gives a complete picture of the color being defined as 4 bytes:

Colors are presented as packed ints consisting of 4 bytes: alpha, red, green, blue. (...) Components are stored as follows (alpha <24) | (red <16) | (green <8) | Blue colour.

Source: android.graphics.Color reference.

// Edit: with HSV values ​​it seems to work fine. I got a different result for "magenta" as the closest match, although purple instead of pink. Maybe you should double check the values ​​and the breakpoint. For example, I can imagine that it would be better to normalize the "H" part. This is for you...

private String getBestMatchingHsvColor(int pixelColor) {
    // largest difference is 360(H), 1(S), 1(V)
    float currentDifference = 360 + 1 + 1;
    // name of the best matching colour
    String closestColorName = null;
    // get HSV values for the pixel colour
    float[] pixelColorHsv = new float[3];
    Color.colorToHSV(pixelColor, pixelColorHsv);

    Iterator<String> colorNameIterator = mColors.keySet().iterator();
    // continue iterating if the map contains a next colour and the difference is greater than zero.
    // a difference of zero means we've found an exact match, so there not point in iterating further.
    while (colorNameIterator.hasNext() && currentDifference > 0) {
        // this colour name
        String currentColorName = colorNameIterator.next();
        // this colour int value
        int color = mColors.get(currentColorName);
        // get HSV values for this colour
        float[] colorHsv = new float[3];
        Color.colorToHSV(color, colorHsv);
        // calculate sum of absolute differences that indicates how good this match is 
        float difference = Math.abs(pixelColorHsv[0] - colorHsv[0]) + Math.abs(pixelColorHsv[1] - colorHsv[1]) + Math.abs(pixelColorHsv[2] - colorHsv[2]);
        // a smaller difference means a better match, so store it
        if (currentDifference > difference) {
            currentDifference = difference;
            closestColorName = currentColorName;
        }
    }
    return closestColorName;
}

      

+3


source


Since you already have a pixel color value in int. You can extract RGB value using the following methods.

int green = Color.green(pix[i]);
int red   = Color.red(pix[i]);
int blue  = Color.blue(pix[i]);

      



And then compare with the RGB values ​​you have

+1


source







All Articles