简体   繁体   English

在 C# 中将 RGB 颜色转换为最接近的 ACI 颜色

[英]Converting RGB Colors to closest ACI Color in C#

I am currently writing a Programm that interacts with dxf files.我目前正在编写一个与 dxf 文件交互的程序。 Therefore I need a Routine that takes RGB Color Values and gives back the closest Color in the AutoCAD Color Index (ACI)因此,我需要一个程序来获取 RGB 颜色值并返回 AutoCAD 颜色索引 (ACI) 中最接近的颜色

Has anybody some Code or an example how to do that?有没有人有一些代码或示例如何做到这一点? It would be nice if it was in C#, but it is not necessary.如果它是在 C# 中会很好,但它不是必需的。

Thanks in advance.提前致谢。

Take the RGB values of all the ACI colors from some source (for example http://www.jtbworld.com/lisp/DisplayColorProperties.htm ) and create an array of ACI colors.从某个来源(例如http://www.jtbworld.com/lisp/DisplayColorProperties.htm )获取所有 ACI 颜色的 RGB 值并创建一个 ACI 颜色数组。 To get an ACI color by index, simply pick the color from that list.要按索引获取 ACI 颜色,只需从该列表中选择颜色即可。

To do a "closest" match backwards lookup from RGB, simply do a pass over that array and return the color with minimum distance (for example by checking the squared distances of the 3 color channels: if your color is r,g,b and the aci color is R,G,B then the distance is要从 RGB 进行“最接近”匹配向后查找,只需通过该数组并返回具有最小距离的颜色(例如,通过检查 3 个颜色通道的平方距离:如果您的颜色是 r、g、b 和aci 颜色是 R,G,B 那么距离是

dist = (r-R)*(r-R) + (g-G)*(g-G) + (b-B)*(b-B);

Whichever color in the ACI array that has the smallest dist, is the closest match to r,g,b. ACI 数组中具有最小 dist 的颜色与 r,g,b 最接近。

Edit: as has been pointed out: RGB distance isn't good as a visual/perceptive difference.编辑:正如已经指出的那样:RGB 距离作为视觉/感知差异并不好。 To match for visual difference, convert to HSV/HSL or if you are really ambitious a more exotic color space like CIE XYZ where "distance" closely represents similarity.要匹配视觉差异,请转换为 HSV/HSL,或者如果您真的雄心勃勃,则可以使用更奇特的色彩空间,例如 CIE XYZ,其中“距离”密切代表相似性。 There are good libraries these days for color space conversion such as Colorful https://www.nuget.org/packages/Colourful/现在有很好的色彩空间转换库,例如五颜六色的https://www.nuget.org/packages/Colourful/

这是将 RGB 转换为 ACI 的方法

var color = Autodesk.AutoCAD.Colors.Color(r, g, b);

I am not sure if this thread/question is still valid but I have also been looking for some way to convert a color to ACI on the internet, but failed.我不确定这个线程/问题是否仍然有效,但我也一直在寻找某种方法在互联网上将颜色转换为 ACI,但失败了。 In my case, I need a method that preferably avoids external libraries and CAD functions.就我而言,我需要一种最好避免使用外部库和 CAD 函数的方法。

I cannot help with C#.我无法帮助 C#。 I normally work with Lazarus/Free Pascal and after lots of trial I came down with a function that seems to be working quite well for me.我通常与 Lazarus/Free Pascal 一起工作,经过大量试验后,我发现了一个似乎对我来说效果很好的函数。 So I am posting my codes here in case they can be helpful to you or to someone else.所以我在这里发布我的代码,以防它们对您或其他人有所帮助。

My Codes are as follow:我的代码如下:

Function RGB2ACIDXFColor(MyColor : TColor) : Integer ;
Var
   OldCol, LowR, MidR, HiR : String ;
   RCol, GCol, BCol, LowCol, MidCol, HiCol : Integer ;
   StPt, HRatio, VRatio, Hemis : Integer ;
Begin
Result := 10 ;
{Break Color Component (BGR Color)}
{IntToHex & Hex2Dec are functions from Lazarus Libraries}
OldCol := IntToHex(MyColor,6) ;    
BCol := Hex2Dec(Copy(OldCol,1,2)) ;
GCol := Hex2Dec(Copy(OldCol,3,2)) ;
RCol := Hex2Dec(Copy(OldCol,5,2)) ;

{Find Color Component Priorities}
LowCol := RCol ;
LowR := 'R' ;
If (GCol < LowCol) Then
Begin
     LowCol := GCol ;
     LowR := 'G' ;
End; //If
If (BCol < LowCol) Then
Begin
     LowCol := BCol ;
     LowR := 'B' ;
End; //If

HiCol := RCol ;
HiR := 'R' ;
If (GCol > HiCol) Then
Begin
     HiCol := GCol ;
     HiR := 'G' ;
End; //If
If (BCol > HiCol) Then
Begin
     HiCol := BCol ;
     HiR := 'B' ;
End; //If

MidCol := GCol ;
MidR := 'G' ;
If ((HiR = 'G') AND (LowR = 'R')) OR
   ((HiR = 'R') AND (LowR = 'G')) Then
Begin
     MidCol := BCol ;
     MidR := 'B' ;
End; //If
If ((HiR = 'G') AND (LowR = 'B')) OR
   ((HiR = 'B') AND (LowR = 'G')) Then
Begin
     MidCol := RCol ;
     MidR := 'R' ;
End; //If

{Refer to CAD color table}
{Find Color Row}
VRatio := Round((5 * (255 - HiCol)) / 255) ;
VRatio *= 2 ;
{Find Color Hemisphere}
If (LowCol = 0) Then Hemis := 0 Else Hemis := 1 ;

{Find Color Start Column And Incrementation}
If (LowR = 'B') Then
Begin
     HRatio := Round((8 * GCol) / (GCol + RCol)) ;
     Result := 10 ;
End; //If
If (LowR = 'G') Then
Begin
     HRatio := Round((8 * RCol) / (RCol + BCol)) ;
     Result := 170 ;
End; //If
If (LowR = 'R') Then
Begin
     HRatio := Round((8 * BCol) / (BCol + GCol)) ;
     Result := 90 ;
End; //If

HRatio *= 10 ;
Result += HRatio + VRatio + Hemis ;
If (Result > 249) Then Result -= 240 ;
End; //Sub

I am sure you will be able to translate that into C#, and hope that this will be useful to somebody.我相信您将能够将其翻译成 C#,并希望这对某人有用。

Cheers,干杯,

J-Eric J. J-埃里克J。

I wouldn't bother with a hard-coded array of ACI colors as Anders proposes.我不会像安德斯提议的那样使用硬编码的 ACI 颜色数组。 You can get an AutoCAD Color object from each legal index and extract the RGB values from that as a System.Drawing.Color with the ColorValue property.您可以从每个合法索引中获取一个 AutoCAD Color对象,并从中提取 RGB 值作为具有ColorValue属性的System.Drawing.Color

Here's a full solution based on the rest of Anders' response, substituting Math.Pow(r - R, 2) for (r - R)*(r - R) since it seems to me to more clearly express the Pythagorean intent of the "distance" calculation.这是一个基于 Anders 其余部分的完整解决方案,用Math.Pow(r - R, 2)代替(r - R)*(r - R)因为在我看来更清楚地表达了“距离”计算。

byte r = 1, g = 203, b = 103; // input color
double minDist = double.MaxValue;
short match = 0; // this will end up with our answer
for (short i = 1; i <= 255; ++i)
{
    var color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(ColorMethod.ByAci, i);
    System.Drawing.Color rgb = color.ColorValue;
    double dist =
        Math.Pow(r - rgb.R, 2) +
        Math.Pow(g - rgb.G, 2) +
        Math.Pow(b - rgb.B, 2);
    if (dist < minDist)
    {
        minDist = dist;
        match = i;
    }
}

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

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