w-ll
w-ll

Reputation: 3915

trying to convert rgb from a .net Color to a string such as "red" or "blue"

All of my methods are failing me in various ways. different lighting can mess it all up too.

has anyone every trying to return a name given a rgb value? "red" "green" "blue" would be enough to satisfy my needs for today.

i have unsafe byte processing of images from my web cam.

webcam

colors

Upvotes: 8

Views: 7970

Answers (6)

giganoide
giganoide

Reputation: 19

Something like this might be helpful:

using System;
using System.Drawing;
                    
public class Program
{
    public static void Main()
    {
        Color color = Color.FromArgb(230, 250, 230);
        Console.WriteLine(GetDescription(color));
    }
    
    public static string GetDescription(Color color)
    {
        var hue = color.GetHue();
        var brightness = color.GetBrightness();
        var saturation = color.GetSaturation();
        
        Console.WriteLine($"H:{hue} B:{brightness} S:{saturation}");
        
        if (brightness > 95)
            return "White";
        if (brightness < 0.1 && saturation < 5)
            return "Black";
        if (hue == 0 && brightness > 0.1 && saturation < 5)
            return "Grey";
        
        if (hue > 330)
            return "Red";
        if (hue < 30)
            return "Red";
        if (hue > 30 && hue < 90)
            return "Yellow";
        if (hue > 90 && hue < 150)
            return "Green";
        if (hue > 150 && hue < 210)
            return "Cyan";
        if (hue > 210 && hue < 270)
            return "Blue";
        if (hue > 270 && hue < 330)
            return "Magenta";
        return "ND";
    }   
}

The idea is to associate descriptors to hue ranges.

To cover the cases of black, white and grey it is also necessary to take into consideration the saturation and brightness (some adjustment of the limits may be necessary).

Upvotes: 0

TaW
TaW

Reputation: 54433

Here is a simple name scheme using two qualifiers and a color name:

string ColorName(Color c)
{
    List<float> hues = new List<float>()
    { 0, 15, 35, 44, 54, 63, 80, 160, 180, 200, 244, 280, 350, 360};
    List<string> hueNames = new List<string>()
        { "red", "orange-red", "orange", "yellow-orange", "yellow",
          "yellow-green",   "green"  , "blue-green" , "cyan", "blue", 
          "violet", "purple", "red" };

    float h = c.GetHue();
    float s = c.GetSaturation();
    float b = (c.R * 0.299f + c.G * 0.587f + c.B *0.114f) / 256f;

    string name = s < 0.35f ? "pale " : s > 0.8f ? "vivid " : "";
    name += b < 0.35f ? "dark " : b > 0.8f ? "light " : "";
    for (int i = 0; i < hues.Count - 1; i++)
        if (h >= hues[i] && h <= hues[i+1] )
        {
            name += hueNames[i];
            break;
        }
    return name;
}

You can easily adapt it if you want the blues to be more differentiated etc..

Upvotes: 1

satya
satya

Reputation: 33

You can try this code

static char[] hexDigits = {
         '0', '1', '2', '3', '4', '5', '6', '7',
         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};



public static string ColorToHexString(Color color)
        {
            byte[] bytes = new byte[4];
            bytes[0] = color.A;
            bytes[1] = color.R;
            bytes[2] = color.G;
            bytes[3] = color.B;
            char[] chars = new char[bytes.Length * 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                int b = bytes[i];
                chars[i * 2] = hexDigits[b >> 4];
                chars[i * 2 + 1] = hexDigits[b & 0xF];
            }
            return new string(chars);
        }

Upvotes: 3

Jonathan Schuster
Jonathan Schuster

Reputation: 2390

I personally find it more natural to think of colors in terms of hue/saturation/brightness than RGB values, and I think that would work well for you in this case. Try this:

Assign color names to certain ranges of the spectrum, as you see fit. For example, maybe red is 0-39, orange is 40-79, etc. (those are arbitrary numbers - I have no idea if they fit on any kind of scale or not). Then calculate the hue from your RGB value (you can find a formula here, although there may be others). Once you know the hue, you know what range of the spectrum it's in, and you can give it a name.

Upvotes: 2

Marc Gravell
Marc Gravell

Reputation: 1062550

Well, Red/Green/Blue are fairly easy to identify by inspection; what range of values do you need to support?

The problem is that unless you start with a named color, it is very hard to get back to one; IsNamedColor will return false even if you create an obvious color via FromArgb.

If you only need the actual expected standard colors, you could enumerate the known colors via reflection?

        Color test = Color.FromArgb(255,0,0);
        Color known = (
                   from prop in typeof(Color)
                       .GetProperties(BindingFlags.Public | BindingFlags.Static)
                   where prop.PropertyType == typeof(Color)
                   let color = (Color)prop.GetValue(null, null)
                   where color.A == test.A && color.R == test.R
                     && color.G == test.G && color.B == test.B
                   select color)
                   .FirstOrDefault();

        Console.WriteLine(known.Name);

You might also be able to use this approach as a source of known colors for a more sophisticated algorithm.

Upvotes: 0

Brian
Brian

Reputation: 118865

If you have a list of known colors with names, you can see which of those known colors a given target color is 'closest' to, using a 'closeness' function along the lines of (F# code):

let Diff (c1:Color) (c2:Color) =
    let dr = (c1.R - c2.R) |> int
    let dg = (c1.G - c2.G) |> int
    let db = (c1.B - c2.B) |> int
    dr*dr + dg*dg + db*db

Whichever one of the known colors has the smallest diff to the target color you want to name, use that name.

Upvotes: 5

Related Questions