比较c#中的RGB颜色

Posted

技术标签:

【中文标题】比较c#中的RGB颜色【英文标题】:Compare RGB colors in c# 【发布时间】:2011-04-27 11:02:01 【问题描述】:

我正在尝试找到一种方法来比较两种颜色,以了解它们的相似程度。我似乎无法找到有关该主题的任何资源,所以我希望在这里得到一些指示。

理想情况下,我想得到一个分数,说明他们有多相似。例如,0 到 100,其中 100 相等,0 则完全不同。

谢谢!

编辑:

从答案中了解更多关于颜色的信息我知道我的问题有点含糊。我将尝试解释我需要这个。

我有一个 800x600 大小的应用程序窗口的像素数据(位置和颜色),因此我可以通过检查每个 x 间隔来确定某个窗口是否打开。

但是,一旦调整应用程序的大小(内容被缩放,而不是移动),此方法就会失败。我可以计算出像素移动的位置,但由于四舍五入和抗锯齿,颜色可能会略有不同。

在这种情况下,Pieter 的解决方案对我来说已经足够好了,尽管所有其他回复也非常有帮助,所以我只是对每个人都投了赞成票。从专业的角度来看,我确实认为 ColorEye 的答案是最准确的,所以我将其标记为答案。

【问题讨论】:

你对相似的定义是什么? 你真的应该告诉我们你想在这里完成什么?您是根据人眼的感知进行区分,还是有其他需要? 【参考方案1】:

您要查找的内容称为Delta-E

http://www.colorwiki.com/wiki/Delta_E:_The_Color_Difference

它是 LAB 颜色空间中两种颜色之间的距离。据说人眼无法区分1 DeltaE以下的颜色(我发现我的眼睛可以发现1 DeltaE以下的颜色差异,每个人都不一样。)

“色差”有 4 个公式。

Delta E (CIE 1976) Delta E (CIE 1994) Delta E (CIE 2000) 三角洲 E (CMC)

检查此站点上的数学链接:

http://www.brucelindbloom.com/

因此,正确的答案是使用给定的公式将 RGB 转换为 LAB,然后使用 DeltaE 1976 来确定颜色的“差异”。结果为 0 表示颜色相同。任何大于 0 的值都可以通过“大多数人无法区分 1 或更小的 delta e”规则来判断。

【讨论】:

谢谢你的回复,我怕事情会这么复杂。我会标记你的答案,因为它是最准确的,尽管可能会像彼得的解决方案一样。 这个网站有一些有用的转换算法(见easyrgb.com/index.php?X=MATH和easyrgb.com/index.php?X=DELT)。 请注意,在 Lab 颜色空间中,CIE 1976 只是点之间的欧几里得距离,所以 DE = sqrt((L2-L1)^2 + (a2-a1)^2 + (b2-b1)^2)【参考方案2】:

有一个开源 .net 库可让您轻松完成此操作:https://github.com/hvalidi/ColorMine

比较颜色最常用的方法是CIE76:

var a = new Rgb  R = 149, G = 13, B = 12 
var b = new Rgb  R = 255, G = 13, B = 12 

var deltaE = a.Compare(b,new Cie1976Comparison());

【讨论】:

【参考方案3】:

颜色具有影响人眼的不同权重。 因此,使用计算的权重将颜色转换为灰度:

灰色 = .11 * B + .59 * G + .30 * R

你的区别将是

差异 = (GrayColor1 - GrayColor2) * 100.0 / 255.0

差值范围为 0-100。

这实际上是一种常用且非常简单的方法,用于在图像处理中计算图像差异。

-编辑 这是非常简单且仍然可用的公式 - 即使在商业应用中也是如此。 如果您想深入了解,您应该查看名为:CIE1976、CIE1994、CIE2000 和 CMC 的色差方法 在这里您可以找到一些更详细的信息: http://en.wikipedia.org/wiki/Color_difference

【讨论】:

是的,没错。但它是基本的,它适用于现实世界。用更多信息编辑了答案。 要得到 0-100 的结果,除数必须是 255 而不是 256。我会修正答案。 范围不能为 0-100,因为如果您有 RGB = (0,0,0) 并将其与另一种颜色进行比较,结果将始终为负。所以实际范围将是 -100 - 100,除非文本中的某些信息丢失。【参考方案4】:

将 RGB 颜色转换为 HSL 颜色空间通常会产生良好的效果。检查***的转换公式。您可以为 H(颜色)、S(颜色的“深度”程度)和 L(颜色的亮度)之间的差异分配权重。

【讨论】:

重量 L 肯定比其他人重。我们的眼睛对亮度变化比对颜色变化更敏感。【参考方案5】:

类似这样的:

    public static int CompareColors(Color a, Color b)
    
        return 100 * (int)(
            1.0 - ((double)(
                Math.Abs(a.R - b.R) +
                Math.Abs(a.G - b.G) +
                Math.Abs(a.B - b.B)
            ) / (256.0 * 3))
        );
    

【讨论】:

谢谢,我想我现在可以从这个开始工作,尽管我需要看看这有多准确。不过,您的代码中有一些错误(256 应该是 255,并且将结果转换为 int 也不是很聪明:D) 虽然从数学上讲这不是一个好主意,因为它没有考虑颜色是如何被感知的。您可以轻松找到相似但得分较低的颜色对,以及不同但得分较高的颜色。 是的,你是对的。你可以全力以赴,但这是一种快速而肮脏的方式来获得近似的差异。我认为“正确”的比较方法需要几页:)。 我不同意反对这个答案的人。虽然不如 ColorEyes 的回答准确,但这对我仍然有用。 @SaphuA:在某些情况下它可能是“正确的”,但它仍然是非常错误的。举个简单的例子,颜色 0x7f0000 和 0x007f00 将产生(大约)与比较 0xb2b2b2 和 0xffffff 相同的结果。换句话说:鲜红色和鲜绿色被认为与白色和浅灰色一样接近。这可能不是您想要的结果。【参考方案6】:

我found 一个有趣的方法称为颜色度量并将其改编为 C#

public static double ColourDistance(Color e1, Color e2)

    long rmean = ((long)e1.R + (long)e2.R) / 2;
    long r = (long)e1.R - (long)e2.R;
    long g = (long)e1.G - (long)e2.G;
    long b = (long)e1.B - (long)e2.B;
    return Math.Sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8));

【讨论】:

【参考方案7】:

颜色感知取决于许多因素,并且可以通过多种方式测量相似度。仅比较 R、G 和 B 组件的相似程度通常会得出人类不会同意的结果。

有一些general material on colour comparisons in wikipedia,并在this question 中使用C# 中的natural colour spaces。

【讨论】:

【参考方案8】:

我已将 Bruce Lindbloom 页面上的 DeltaE2000 代码翻译成 C。

这里:

     //
     //  deltae2000.c
     //
     //  Translated by Dr Cube on 10/1/16.
     //  Translated to C from this javascript code written by Bruce LindBloom:
     //    http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE2000.html
     //    http://www.brucelindbloom.com/javascript/ColorDiff.js

     #include <stdio.h>
     #include <math.h>

     #define Lab2k struct Lab2kStruct
     Lab2k
     
        float L;
        float a;
        float b;
     ;

     // function expects Lab where: 0 >= L <=100.0 , -100 >=a <= 100.0  and  -100 >= b <= 100.0

     float
     DeltaE2000(Lab2k Lab1,Lab2k Lab2)
     
        float kL = 1.0;
        float kC = 1.0;
        float kH = 1.0;
        float lBarPrime = 0.5 * (Lab1.L + Lab2.L);
        float c1 = sqrtf(Lab1.a * Lab1.a + Lab1.b * Lab1.b);
        float c2 = sqrtf(Lab2.a * Lab2.a + Lab2.b * Lab2.b);
        float cBar = 0.5 * (c1 + c2);
        float cBar7 = cBar * cBar * cBar * cBar * cBar * cBar * cBar;
        float g = 0.5 * (1.0 - sqrtf(cBar7 / (cBar7 + 6103515625.0)));  /* 6103515625 = 25^7 */
        float a1Prime = Lab1.a * (1.0 + g);
        float a2Prime = Lab2.a * (1.0 + g);
        float c1Prime = sqrtf(a1Prime * a1Prime + Lab1.b * Lab1.b);
        float c2Prime = sqrtf(a2Prime * a2Prime + Lab2.b * Lab2.b);
        float cBarPrime = 0.5 * (c1Prime + c2Prime);
        float h1Prime = (atan2f(Lab1.b, a1Prime) * 180.0) / M_PI;
        float dhPrime; // not initialized on purpose

        if (h1Prime < 0.0)
           h1Prime += 360.0;
        float h2Prime = (atan2f(Lab2.b, a2Prime) * 180.0) / M_PI;
        if (h2Prime < 0.0)
           h2Prime += 360.0;
        float hBarPrime = (fabsf(h1Prime - h2Prime) > 180.0) ? (0.5 * (h1Prime + h2Prime + 360.0)) : (0.5 * (h1Prime + h2Prime));
        float t = 1.0 -
        0.17 * cosf(M_PI * (      hBarPrime - 30.0) / 180.0) +
        0.24 * cosf(M_PI * (2.0 * hBarPrime       ) / 180.0) +
        0.32 * cosf(M_PI * (3.0 * hBarPrime +  6.0) / 180.0) -
        0.20 * cosf(M_PI * (4.0 * hBarPrime - 63.0) / 180.0);
        if (fabsf(h2Prime - h1Prime) <= 180.0)
           dhPrime = h2Prime - h1Prime;
        else
           dhPrime = (h2Prime <= h1Prime) ? (h2Prime - h1Prime + 360.0) : (h2Prime - h1Prime - 360.0);
        float dLPrime = Lab2.L - Lab1.L;
        float dCPrime = c2Prime - c1Prime;
        float dHPrime = 2.0 * sqrtf(c1Prime * c2Prime) * sinf(M_PI * (0.5 * dhPrime) / 180.0);
        float sL = 1.0 + ((0.015 * (lBarPrime - 50.0) * (lBarPrime - 50.0)) / sqrtf(20.0 + (lBarPrime - 50.0) * (lBarPrime - 50.0)));
        float sC = 1.0 + 0.045 * cBarPrime;
        float sH = 1.0 + 0.015 * cBarPrime * t;
        float dTheta = 30.0 * expf(-((hBarPrime - 275.0) / 25.0) * ((hBarPrime - 275.0) / 25.0));
        float cBarPrime7 = cBarPrime * cBarPrime * cBarPrime * cBarPrime * cBarPrime * cBarPrime * cBarPrime;
        float rC = sqrtf(cBarPrime7 / (cBarPrime7 + 6103515625.0));
        float rT = -2.0 * rC * sinf(M_PI * (2.0 * dTheta) / 180.0);
        return(sqrtf(
                           (dLPrime / (kL * sL)) * (dLPrime / (kL * sL)) +
                           (dCPrime / (kC * sC)) * (dCPrime / (kC * sC)) +
                           (dHPrime / (kH * sH)) * (dHPrime / (kH * sH)) +
                           (dCPrime / (kC * sC)) * (dHPrime / (kH * sH)) * rT
                      )
         );
     

【讨论】:

以上是关于比较c#中的RGB颜色的主要内容,如果未能解决你的问题,请参考以下文章

c# 颜色RGB到HSB互相转换

如何计算位图的平均 rgb 颜色值

如何将 RGB 颜色转换为 HSV?

RGB颜色函数-RGB()颜色函数

平面设计中的金色字体是怎么调的,RGB或者CMYK值是多少

c# winform 如何实现16进制颜色值的转换