简体   繁体   English

在Android中拥有Hue时查找颜色名称

[英]Find color name when have Hue in android

I only care about 12 colors: 我只关心12种颜色:

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 bitmap, i can get the Hue value: 当我读取位图的像素时,我可以得到Hue值:

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 color of this pixel (only in 12 above colors)? 现在我想知道这个像素的颜色(只有12种颜色)?

I use HSV to see the range of color. 我使用HSV来查看颜色范围。 When i have a color which doesn't in this list, i want to name it as similarly color in my list How can i do it? 如果我的颜色不在此列表中,我想在列表中将其命名为类似颜色我该怎么办?

Thanks you so much 非常感谢

Based on your comments it seems you're basically trying to reduce the bitmap's full colour palette to only the 12 you specified. 根据您的评论,您似乎基本上尝试将位图的全色调色板减少到仅指定的12个。 Obviously for every pixel in the bitmap the 'best match' from those 12 should be picked. 显然,对于位图中的每个像素,应该选择来自那些12的“最佳匹配”。

I still don't see why you would need the HSV values, as it's just a different representation of the RGB components - it doesn't actually change the problem, or its solution. 我仍然不明白为什么你需要HSV值,因为它只是RGB组件的不同表示 - 它实际上并没有改变问题或其解决方案。

A straightforward approach to find the best match for any RGB colour would look something like as follows. 找到任何RGB颜色的最佳匹配的直接方法看起来如下所示。

First build some sort of a list containing the colours you want to match against. 首先构建一些包含要匹配的颜色的列表。 I've used a Map, since you mentioned you (also) wanted to know the name of the colour, not just the RGB value. 我使用了Map,因为你提到你(也)想知道颜色的名称 ,而不仅仅是RGB值。

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 make a method that will tell you the best match. 然后制作一个方法,告诉你最佳匹配。 You can call this from within your second for loop and pass it the current pixel colour. 您可以在第二个for循环中调用它并将其传递给当前像素颜色。 I've added some inline comments to explain the different steps, but it's 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's no point in iterating further.
    while (colorNameIterator.hasNext() && currentDifference > 0) {
        // this colour's name
        String currentColorName = colorNameIterator.next();
        // this colour's 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;
}

The results for a quick test using some of the 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 inbetween the brackets is the actual int value for the Color constant, the second is the int value for the best match found, with the name right in front of it. 括号中的第一个数字是Color常量的实际int值,第二个是找到的最佳匹配的int值,名称在它前面。

The result for Color.MAGENTA also illustrates why you should not just compare the colour's int value directly. Color.MAGENTA的结果也说明了为什么不应该直接比较颜色的int值。 The actual int value is -65281 , which is quite close to the value for Color.RED (-65536). 实际的int值是-65281 ,它非常接近Color.RED (-65536)的值。 However, the best match based on the different components is 'pink', which has a -16181 value. 但是,基于不同组件的最佳匹配是“粉红色”,其值为-16181。 Obviously this makes complete sense knowing that a colour is defined as 4 bytes: 显然,知道颜色定义为4个字节,这就完全有意义:

Colors are represented as packed ints, made up of 4 bytes: alpha, red, green, blue. 颜色表示为打包的int,由4个字节组成:alpha,red,green,blue。 (...) The components are stored as follows (alpha << 24) | (...)组件存储如下(alpha << 24)| (red << 16) | (红色<< 16)| (green << 8) | (绿色<< 8)| blue. 蓝色。

Source: android.graphics.Color reference. 来源:android.graphics.Color参考。

// Edit: with HSV values it seems to work fine too. //编辑:使用HSV值似乎也能正常工作。 I did get a different result for 'magenta' as closest match though - violet, in stead of pink. 我确实得到了与“洋红色”不同的结果作为最接近的匹配 - 紫罗兰色,而不是粉红色。 You might want to double check the values and breakpoint some stuff. 您可能想要仔细检查值并断点一些东西。 For instance, I can imagine it might be better to normalize the 'H' part. 例如,我可以想象将“H”部分标准化可能会更好。 That's up to 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's 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's not point in iterating further.
    while (colorNameIterator.hasNext() && currentDifference > 0) {
        // this colour's name
        String currentColorName = colorNameIterator.next();
        // this colour's 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;
}

Since you already have pixel color value in int. 由于你已经在int中有像素颜色值。 You can extract the RGB value using following methods 您可以使用以下方法提取RGB值

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 然后与您拥有的RGB值进行比较

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM