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

发布于 2024-12-03 12:44:43 字数 149 浏览 2 评论 0原文

我目前正在编写一个与 dxf 文件交互的程序。因此,我需要一个例程,它采用 RGB 颜色值并返回 AutoCAD 颜色索引 (ACI) 中最接近的颜色

有没有人有一些代码或示例如何做到这一点?如果它是用 C# 编写的就好了,但这不是必需的。

提前致谢。

I am currently writing a Programm that interacts with dxf files. Therefore I need a Routine that takes RGB Color Values and gives back the closest Color in the AutoCAD Color Index (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.

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

相对绾红妆 2024-12-10 12:44:43

从某个来源获取所有 ACI 颜色的 RGB 值(例如 http://www.jtbworld .com/lisp/DisplayColorProperties.htm)并创建 ACI 颜色数组。要按索引获取 ACI 颜色,只需从该列表中选择颜色即可。

要从 RGB 进行“最接近”匹配向后查找,只需遍历该数组并返回具有最小距离的颜色(例如,通过检查 3 个颜色通道的平方距离:如果您的颜色是 r、g、b 且aci 颜色是 R、G、B,则距离是

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

ACI 数组中具有最小距离的颜色与 r、g、b 最接近的匹配

编辑:正如已经指出的:RGB 距离不好。作为视觉/感知为了匹配视觉差异,请转换为 HSV/HSL,或者如果您确实想要更奇特的色彩空间,例如 CIE XYZ,其中“距离”密切代表相似性,现在有一些很好的色彩空间转换库,例如 Colorful https://www.nuget.org/packages/Colourful/

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. To get an ACI color by index, simply pick the color from that list.

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

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.

Edit: as has been pointed out: RGB distance isn't good as a visual/perceptive difference. 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. There are good libraries these days for color space conversion such as Colorful https://www.nuget.org/packages/Colourful/

旧瑾黎汐 2024-12-10 12:44:43

我不会像 Anders 所建议的那样使用硬编码的 ACI 颜色数组。您可以从每个合法索引中获取 AutoCAD Color 对象,并使用 ColorValue 属性从该对象中提取 RGB 值作为 System.Drawing.Color

这是基于 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;
    }
}

I wouldn't bother with a hard-coded array of ACI colors as Anders proposes. 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.

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.

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;
    }
}
戒ㄋ 2024-12-10 12:44:43

以下是将 RGB 转换为 ACI 的方法

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

Here is how you convert RGB to ACI

var color = Autodesk.AutoCAD.Colors.Color(r, g, b);
旧梦荧光笔 2024-12-10 12:44:43

我不确定这个线程/问题是否仍然有效,但我也一直在互联网上寻找某种将颜色转换为 ACI 的方法,但失败了。就我而言,我需要一种最好避免外部库和 CAD 函数的方法。

我无法帮助 C#。我通常使用 Lazarus/Free Pascal,经过大量试验后,我得到了一个似乎对我来说工作得很好的函数。因此,我在这里发布我的代码,以防它们对您或其他人有帮助。

我的代码如下:

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

我相信您能够将其翻译成 C#,并希望这对某人有用。

干杯,

J-埃里克·J。

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. In my case, I need a method that preferably avoids external libraries and CAD functions.

I cannot help with 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. 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.

Cheers,

J-Eric J.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文