背景:RGB值(R,G,B)转颜色简单,直接用Color.FromArgb(R,G,B)即可实现,但是本文要讲的是,给定一个(R,G,B),要求不转换成Color也能直观的知道它是属于哪一种颜色(比如LED灯颜色自动判断是否OK)。RGB2Name就是这样一种实现的方法。
C#中已分类的颜色种类从AliceBlue(240,248,255)到YellowGreen(154,205,50)一共有140种,实际上颜色有256*256*256=1600多万种,所以随便给定一个(R,G,B),只靠系统中已定义的颜色种类来匹配显然不够。
但是可不可以用这140种颜色来模糊匹配呢,答案是可以的,但是模糊匹配的算法我不再行,有好的模糊匹配的算法也请跟我说一下。本文用的是另外一种算法更简单的方法,只设定有28种颜色:
红(深中浅),绿(深中浅),蓝(深中浅),黄(深中浅),青(深中浅),紫(深中浅),橙,黄绿,青绿,青蓝,紫蓝,紫红,黑,灰,浅灰,白
枚举如下:
public enum RGBName
{
[Description("红")]
Red = 1,
[Description("绿")]
Green,
[Description("蓝")]
Blue,
[Description("深红")]
DarkRed,
[Description("深绿")]
DarkGreen,
[Description("深蓝")]
DarkBlue,
[Description("浅红")]
LightRed,
[Description("浅绿")]
LightGreen,
[Description("浅蓝")]
LightBlue,
[Description("黄")]
Yellow,
[Description("青")]
Cyan,
[Description("紫")]
Purple,
[Description("深黄")]
DarkYellow,
[Description("深青")]
DarkCyan,
[Description("深紫")]
DarkPurple,
[Description("浅黄")]
LightYellow,
[Description("浅青")]
LightCyan,
[Description("浅紫")]
LightPurple,
[Description("橙")]
Orange,
[Description("黄绿")]
YellowGreen,
[Description("青绿")]
CyanGreen,
[Description("青蓝")]
CyanBlue,
[Description("紫蓝")]
PurpleBlue,
[Description("紫红")]
PurpleRed,
[Description("黑")]
Black,
[Description("白")]
White,
[Description("灰")]
Gray,
[Description("浅灰")]
LightGray,
}
然后将255分成4个等级,x/83整除四舍五入取整~0,1,2,3
排列组合:(r,g,b)=4*4*4=64种情况
针对这64种情况,规律如下:
public static string CLRToName(Color Clr)
{
double d_r = (double)Clr.R / 83;
double d_g = (double)Clr.G / 83;
double d_b = (double)Clr.B / 83;
int r = (int)Math.Round(d_r);
int g = (int)Math.Round(d_g);
int b = (int)Math.Round(d_b);
string rgb = r.ToString() + "," + g.ToString() + "," + b.ToString();
#region "switch (rgb)"
switch (rgb)
{
case "0,0,0":
case "1,1,1":
case "2,2,2":
case "3,3,3":
if (r == 0) return RGBName.Black.GetDescription();
if (r == 1) return RGBName.Gray.GetDescription();
if (r == 2) return RGBName.LightGray.GetDescription();
if (r == 3) return RGBName.White.GetDescription();
break;
case "0,0,3":
case "0,3,0":
case "3,0,0":
case "1,1,3":
case "1,3,1":
case "3,1,1":
case "0,1,3":
case "0,3,1":
case "3,0,1":
case "1,0,3":
case "1,3,0":
case "3,1,0":
case "0,0,2":
case "0,2,0":
case "2,0,0":
case "1,1,2":
case "1,2,1":
case "2,1,1":
case "0,1,2":
case "0,2,1":
case "2,0,1":
case "1,0,2":
case "1,2,0":
case "2,1,0":
if (r == 2) return RGBName.DarkRed.GetDescription();
if (g == 2) return RGBName.DarkGreen.GetDescription();
if (b == 2) return RGBName.DarkBlue.GetDescription();
if (r == 3) return RGBName.Red.GetDescription();
if (g == 3) return RGBName.Green.GetDescription();
if (b == 3) return RGBName.Blue.GetDescription();
break;
case "0,0,1":
case "0,1,0":
case "1,0,0":
case "2,2,3":
case "2,3,2":
case "3,2,2":
if (r == 1) return RGBName.DarkRed.GetDescription();
if (g == 1) return RGBName.DarkGreen.GetDescription();
if (b == 1) return RGBName.DarkBlue.GetDescription();
if (r == 3) return RGBName.LightRed.GetDescription();
if (g == 3) return RGBName.LightGreen.GetDescription();
if (b == 3) return RGBName.LightBlue.GetDescription();
break;
case "1,1,0":
case "0,1,1":
case "1,0,1":
case "2,2,0":
case "0,2,2":
case "2,0,2":
case "2,2,1":
case "1,2,2":
case "2,1,2":
case "3,3,0":
case "0,3,3":
case "3,0,3":
case "3,3,1":
case "1,3,3":
case "3,1,3":
case "3,3,2":
case "2,3,3":
case "3,2,3":
if (r == 1 && g == 1) return RGBName.DarkYellow.GetDescription();
if (g == 1 && b == 1) return RGBName.DarkCyan.GetDescription();
if (r == 1 && b == 1) return RGBName.DarkPurple.GetDescription();
if (r == 2 && g == 2) return RGBName.Yellow.GetDescription();
if (g == 2 && b == 2) return RGBName.Cyan.GetDescription();
if (r == 2 && b == 2) return RGBName.Purple.GetDescription();
if (r == 3 && g == 3) return RGBName.LightYellow.GetDescription();
if (g == 3 && b == 3) return RGBName.LightCyan.GetDescription();
if (r == 3 && b == 3) return RGBName.LightPurple.GetDescription();
break;
case "3,2,0":
case "3,2,1":
return RGBName.Orange.GetDescription();
case "2,3,0":
case "2,3,1":
return RGBName.YellowGreen.GetDescription();
case "0,3,2":
case "1,3,2":
return RGBName.CyanGreen.GetDescription();
case "0,2,3":
case "1,2,3":
return RGBName.CyanBlue.GetDescription();
case "3,0,2":
case "3,1,2":
return RGBName.PurpleRed.GetDescription();
case "2,0,3":
case "2,1,3":
return RGBName.PurpleBlue.GetDescription();
default:
return "Error";
}
#endregion
return "Error";
}
上面的GetDescription()是扩展类自定义函数,获取枚举的描述信息。完整代码文件链接为:Github,感兴趣的可以下载。
为了方便集成:用List存储RGBN信息
public static List <string> CLR2RGBN(Color Clr)
{
List<string> list = new List<string>();
list.Add(Clr.R.ToString());
list.Add(Clr.G.ToString());
list.Add(Clr.B.ToString());
list.Add(CLRToName(Clr));
return list;
}
然后写了一个测试函数:
private static void Test()
{
foreach (var item in typeof(Color).GetMembers())
{
if (item.MemberType == System.Reflection.MemberTypes.Property && System.Drawing.Color.FromName(item.Name).IsKnownColor == true)
//只取属性且为属性中的已知Color,剔除byte属性以及一些布尔属性等(A B G R IsKnownColor Name等)
{
Color Clr = Color.FromName(item.Name);
List<string> list = CLR2RGBN(Clr);
string rgbn = item.Name + "(" + list[0] + "," + list[1] + "," + list[2] + "):" + list[3];
Console.WriteLine(rgbn);
}
}
}
这个测试函数会把系统分类的140种颜色输入到CLR2RGBN()函数中,最后输出形如:
AliceBlue(240,248,255):白
AntiqueWhite(250,235,215):白
Aqua(0,255,255):浅青
Aquamarine(127,255,212):浅青
Azure(240,255,255):白
Beige(245,245,220):白
Bisque(255,228,196):浅黄
Black(0,0,0):黑
BlanchedAlmond(255,235,205):浅黄
Blue(0,0,255):蓝
BlueViolet(138,43,226):紫蓝
Brown(165,42,42):深红
BurlyWood(222,184,135):浅红
CadetBlue(95,158,160):青
Chartreuse(127,255,0):黄绿
Chocolate(210,105,30):红
Coral(255,127,80):橙
CornflowerBlue(100,149,237):青蓝
Cornsilk(255,248,220):白
Crimson(220,20,60):红
Cyan(0,255,255):浅青
。。。
Tan(210,180,140):浅红
Teal(0,128,128):青
Thistle(216,191,216):浅紫
Tomato(255,99,71):红
Turquoise(64,224,208):浅青
Violet(238,130,238):浅紫
Wheat(245,222,179):浅黄
White(255,255,255):白
WhiteSmoke(245,245,245):白
Yellow(255,255,0):浅黄
YellowGreen(154,205,50):黄
通过对比发现,系统分类的颜色,和匹配的中文描述,相识度90%以上。没有达到100%,还有优化的空间。
但是对于一般的应用而言已经足够了,如通过颜色分析测试仪读LED灯读出来的RGB可以算出它属于28个颜色中的哪一个,从而进一步自动判断待测物颜色是否符合要求。