如何比较两种颜色的相似性/差异性

230
我想设计一个程序,可以帮助我评估5种预定义的颜色中哪种更类似于变量颜色,并给出相似度百分比。问题是我不知道如何逐步手动完成这个过程,因此想要设计一个程序更加困难。
更多细节:这些颜色来自具有不同颜色的凝胶管的照片。我有5个不同颜色的管子,每个代表5个级别中的1个。我想拍摄其他样品的照片,并在计算机上通过比较颜色来评估该样品属于哪个级别,并且我还想知道其近似百分比。我希望程序能够像这样实现:http://www.colortools.net/color_matcher.html 如果您能告诉我需要采取哪些步骤,即使这些步骤是我需要手动思考和执行的事情,也将非常有帮助。

2
我对文本进行了微小的更改,将一个葡萄牙语单词更改为我认为是正确的英语等效词...如果我犯了错误,请将其更改回来。 - Beska
14
有一篇关于颜色差异的维基百科文章:http://en.wikipedia.org/wiki/Color_difference - Ocaso Protal
5
这应该很有趣:http://stevehanov.ca/blog/index.php?id=116它探讨了在三种不同的颜色模型中计算差异的方法。 - Vlad
一些用于颜色对比度检测的不错算法:http://www.splitbrain.org/blog/2008-09/18-calculating_color_contrast_with_php - Kevin
也许Lea Verou的游戏能够帮到你。 - Laurent S.
显示剩余5条评论
20个回答

172

请参阅维基百科关于色差的文章获取正确的引导信息。

基本上,您要在某个多维颜色空间中计算一个距离度量。

但是,RGB不是"感知均匀的",因此 Vadim 建议的欧几里得 RGB 距离度量将不能匹配颜色之间的人类感知距离。首先,L*a*b* 旨在成为一个感知均匀的颜色空间,并且常用 deltaE 度量。但是有更精细的颜色空间和更精细的 deltaE 公式,可以更接近匹配人类感知。

您将需要了解有关颜色空间和光源的更多信息以进行转换。但是,如果您需要一种比欧几里得 RGB 度量更好的快速公式,请执行以下操作:

  • 假设您的 RGB 值在 sRGB 颜色空间中
  • 查找从 sRGBL*a*b* 的转换公式
  • 将您的 sRGB 颜色转换为 L*a*b*
  • 计算两个 L*a*b* 值之间的 deltaE

这并不是计算成本昂贵,只是一些非线性公式和一些乘法和加法。


5
如果你在使用Ruby,可以查看color gem,该gem实现了deltaE和其他颜色操作。 - Mike Jarema
4
以下是该 JavaScript 实现的简要概述 https://gist.github.com/ryancat/9972419b2a78f329ce3aebb7f1a09152 - Ryan.C
对于那些寻找Flutter / Dart实现deltaE的人,有一个包:https://pub.dev/packages/delta_e - maganap
我认为原始的deltaE距离在Lab*空间中只是欧几里得距离。参考链接 - kennysong
一个整洁的JavaScript库实现了各种deltaE算法,可以在这里找到:http://zschuessler.github.io/DeltaE/。该网站还包含[一篇文章](http://zschuessler.github.io/DeltaE/learn/)解释不同算法之间的差异。 - Marten S
这里有一个Kotlin解决方案 - Lifes

59

这只是我脑海中的一个想法(如果很蠢请原谅)。可以将颜色的三个组成部分视为三维坐标点,然后计算点之间的距离。

比如:

Point1 has R1 G1 B1
Point2 has R2 G2 B2

颜色之间的距离是

d=sqrt((r2-r1)^2+(g2-g1)^2+(b2-b1)^2)

百分比是

p=d/sqrt((255)^2+(255)^2+(255)^2)

39
如果我们使用RGB颜色空间,则两种颜色之间的差异并不像人类感知的差异那样相同。但是,基本的想法在任何地方都是相同的 - 我们只需要将其映射到另一个颜色空间(我想是lab)。 - Voo
7
我同意,HSV/HSL/LAB比(s)RGB更适合基于距离的相似匹配。 - Jon Purdy
6
这是一个很好的方法告诉你两种颜色有多不同,但它并不能很好地告诉你它们在感知上有多不同。人类的眼睛远非完美:我们对绿色比红色或蓝色更敏感,我们的亮度感知是对数的等等。原帖没有明确指定需要哪种方式,但可以在这里查看一种专为人类视觉量身定制的算法。 - BlueRaja - Danny Pflughoeft
15
这里的另一个问题是,255、0、0与0、255、0和0、0、255之间的距离相同。请注意,这是一个翻译任务,不包括任何解释或其他附加信息。 - user2102611
1
当将RGB值用作向量时,可以计算这两个向量之间的角度以获得相似性。百分比为角度/360。 - thormeier
显示剩余2条评论

47

实际上,几个月前我也走过同样的路。对于这个问题(在这里问过几次:here),没有完美的答案,但有一个比sqrt(r-r)等答案更复杂且更易直接实现的RGB公式。我在这里找到了这个公式,它是相当复杂的真实公式(由CIE制定,CIE是颜色的W3C,因为这是一项未完成的任务,你可以在那里找到较旧和较简单的颜色差异方程)。祝你好运。

编辑:供后人参考,以下是相关的C代码:

typedef struct {
     unsigned char r, g, b;
} RGB;

double ColourDistance(RGB e1, RGB 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 sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8));
}

26

如果你有两个 Color 对象 c1c2,你可以逐个比较 c1c2 的每个 RGB 值。

int diffRed   = Math.abs(c1.getRed()   - c2.getRed());
int diffGreen = Math.abs(c1.getGreen() - c2.getGreen());
int diffBlue  = Math.abs(c1.getBlue()  - c2.getBlue());

你可以将这些值除以两个饱和度之间的差距(255),这样你就可以得到它们之间的差异。

float pctDiffRed   = (float)diffRed   / 255;
float pctDiffGreen = (float)diffGreen / 255;
float pctDiffBlue   = (float)diffBlue  / 255;

然后您只需要以百分比的形式找到平均颜色差异即可。

(pctDiffRed + pctDiffGreen + pctDiffBlue) / 3 * 100

这将为您提供c1c2之间的百分比差异。


1
还有两点需要修改:<b>1</ b>pctDiffRed = diffRed / 255;将会得到0,除非你在某个地方强制转换为浮点数。 <b>2</ b>你需要在某处乘以100,以获得百分比。 - vaughandroid
20
这可能不会带来最好的“明显”差异,因为人眼对颜色变化的感知方式是不同的。话虽如此,我猜这正是她在寻找的东西,因为她可能正在寻找一个相等可量化的差异,而不是一个感知上的差异。只是想提出这个观点作为需要考虑的内容,以防它相关。 - Beska

24
颜色值具有多个维度,因此没有固定的方法来比较两种颜色。您需要确定对于您的用例,颜色的含义以及如何最好地比较它们。
很可能您想要比较颜色的色调、饱和度和/或亮度属性,而不是红/绿/蓝组件。如果您在确定如何比较它们方面遇到困难,请取一些样本颜色对并在心里进行比较,然后尝试为自己解释/证明它们为什么相似/不同。
一旦您知道要比较颜色的属性/组件,那么您需要确定如何从颜色中提取该信息。
很可能您只需要将颜色从常见的红绿蓝表示法转换为色调、饱和度和亮度,然后计算类似于:
avghue = (color1.hue + color2.hue)/2
distance = abs(color1.hue-avghue)

这个例子会给你一个简单的标量值,指示颜色的渐变/色相之间有多远。

请参见维基百科上关于HSL和HSV的文章


2
根据我在讲座中所记得的,对于这些事情,我会将图像转换为Lab颜色空间,而不是HSV / HSL。选择此选项的任何理由? - Voo
不是。RGB和HSL是我最熟悉的,所以我选择了HSL来强调“默认”的RGB并不是唯一的选择——这真的取决于应用程序。感谢您让我知道Lab颜色空间。 - Supr
1
我还是给你加了1个赞,因为基本原则是要“正确”的答案(将颜色空间转换为能够统一处理感知差异的然后进行比较)。我不太确定哪种颜色空间是最好的 - 在我看来,所有这些不同的颜色空间都很令人困惑。 ;) - Voo

17

比较两种颜色的最佳方法之一是CIE76。差异被称为Delta-E。当它小于1时,肉眼无法识别差异。

有一个很棒的颜色工具类ColorUtils(以下是代码),其中包括CIE76比较方法。它是由苏黎世大学的Daniel Strebel编写的。

我从ColorUtils.class中使用了该方法:

static double colorDifference(int r1, int g1, int b1, int r2, int g2, int b2)

r1,g1,b1 - 第一个颜色的RGB值

r2,g2,b2 - 你想要比较的第二个颜色的RGB值

如果你在使用Android,你可以通过以下方式获取这些值:

r1 = Color.red(pixel);

g1 = Color.green(pixel);

b1 = Color.blue(pixel);


ColorUtils.class由Daniel Strebel,苏黎世大学提供:

import android.graphics.Color;

public class ColorUtil {
public static int argb(int R, int G, int B) {
    return argb(Byte.MAX_VALUE, R, G, B);
}

public static int argb(int A, int R, int G, int B) {
    byte[] colorByteArr = {(byte) A, (byte) R, (byte) G, (byte) B};
    return byteArrToInt(colorByteArr);
}

public static int[] rgb(int argb) {
    return new int[]{(argb >> 16) & 0xFF, (argb >> 8) & 0xFF, argb & 0xFF};
}

public static int byteArrToInt(byte[] colorByteArr) {
    return (colorByteArr[0] << 24) + ((colorByteArr[1] & 0xFF) << 16)
            + ((colorByteArr[2] & 0xFF) << 8) + (colorByteArr[3] & 0xFF);
}

public static int[] rgb2lab(int R, int G, int B) {
    //http://www.brucelindbloom.com

    float r, g, b, X, Y, Z, fx, fy, fz, xr, yr, zr;
    float Ls, as, bs;
    float eps = 216.f / 24389.f;
    float k = 24389.f / 27.f;

    float Xr = 0.964221f;  // reference white D50
    float Yr = 1.0f;
    float Zr = 0.825211f;

    // RGB to XYZ
    r = R / 255.f; //R 0..1
    g = G / 255.f; //G 0..1
    b = B / 255.f; //B 0..1

    // assuming sRGB (D65)
    if (r <= 0.04045)
        r = r / 12;
    else
        r = (float) Math.pow((r + 0.055) / 1.055, 2.4);

    if (g <= 0.04045)
        g = g / 12;
    else
        g = (float) Math.pow((g + 0.055) / 1.055, 2.4);

    if (b <= 0.04045)
        b = b / 12;
    else
        b = (float) Math.pow((b + 0.055) / 1.055, 2.4);


    X = 0.436052025f * r + 0.385081593f * g + 0.143087414f * b;
    Y = 0.222491598f * r + 0.71688606f * g + 0.060621486f * b;
    Z = 0.013929122f * r + 0.097097002f * g + 0.71418547f * b;

    // XYZ to Lab
    xr = X / Xr;
    yr = Y / Yr;
    zr = Z / Zr;

    if (xr > eps)
        fx = (float) Math.pow(xr, 1 / 3.);
    else
        fx = (float) ((k * xr + 16.) / 116.);

    if (yr > eps)
        fy = (float) Math.pow(yr, 1 / 3.);
    else
        fy = (float) ((k * yr + 16.) / 116.);

    if (zr > eps)
        fz = (float) Math.pow(zr, 1 / 3.);
    else
        fz = (float) ((k * zr + 16.) / 116);

    Ls = (116 * fy) - 16;
    as = 500 * (fx - fy);
    bs = 200 * (fy - fz);

    int[] lab = new int[3];
    lab[0] = (int) (2.55 * Ls + .5);
    lab[1] = (int) (as + .5);
    lab[2] = (int) (bs + .5);
    return lab;
}

/**
 * Computes the difference between two RGB colors by converting them to the L*a*b scale and
 * comparing them using the CIE76 algorithm { http://en.wikipedia.org/wiki/Color_difference#CIE76}
 */
public static double getColorDifference(int a, int b) {
    int r1, g1, b1, r2, g2, b2;
    r1 = Color.red(a);
    g1 = Color.green(a);
    b1 = Color.blue(a);
    r2 = Color.red(b);
    g2 = Color.green(b);
    b2 = Color.blue(b);
    int[] lab1 = rgb2lab(r1, g1, b1);
    int[] lab2 = rgb2lab(r2, g2, b2);
    return Math.sqrt(Math.pow(lab2[0] - lab1[0], 2) + Math.pow(lab2[1] - lab1[1], 2) + Math.pow(lab2[2] - lab1[2], 2));
}
}

上面的代码在rgb2lab中存在错误:应该将除以12替换为在r、g和b转换中除以12.92。否则,函数在r = 0.04045处不连续。 - John Smith
这个解决方案几乎完美,但似乎在处理黄色和绿色时给出了错误的答案。例如: getColorDifference( new Color(178, 157, 87), // 黄色 new Color(117, 178, 87) // 绿色 )答案:33.25..getColorDifference( new Color(178, 157, 87), // 较浅的黄色 new Color(140, 115, 31) // 稍微较暗的黄色 );答案:40.9..不知何故,它认为黄色和绿色的版本更接近(尽管在视觉上明显更不同)附带图片: https://imgur.com/yEatRuJ - Joonas Vali

10

这只是另一个回答,虽然它与Supr的回答类似 - 只是使用了不同的颜色空间。

问题在于:人类对颜色的感知并不是统一的,而RGB颜色空间忽略了这一点。因此,如果您使用RGB颜色空间,并且仅计算两种颜色之间的欧几里得距离,您可能会得到一个在数学上绝对正确但与人类的感知不一致的差异。

这可能不是一个问题 - 我认为差别并不大,但如果您想更好地解决这个问题,您应该将RGB颜色转换为专门设计用于避免上述问题的颜色空间。有几种空间可以选择,都是从早期模型中改进而来(由于这基于人类的感知,我们需要根据实验数据测量“正确”的值)。Lab颜色空间我认为是最好的,尽管有点复杂。较简单的是CIE XYZ

这里是一个列出不同颜色空间之间转换公式的网站,您可以进行一些实验。


5

您希望匹配的Kotlin版本百分比是多少。

百分比可选参数的方法调用

isMatchingColor(intColor1, intColor2, 95) // should match color if 95% similar

方法体

private fun isMatchingColor(intColor1: Int, intColor2: Int, percent: Int = 90): Boolean {
    val threadSold = 255 - (255 / 100f * percent)

    val diffAlpha = abs(Color.alpha(intColor1) - Color.alpha(intColor2))
    val diffRed = abs(Color.red(intColor1) - Color.red(intColor2))
    val diffGreen = abs(Color.green(intColor1) - Color.green(intColor2))
    val diffBlue = abs(Color.blue(intColor1) - Color.blue(intColor2))

    if (diffAlpha > threadSold) {
        return false
    }

    if (diffRed > threadSold) {
        return false
    }

    if (diffGreen > threadSold) {
        return false
    }

    if (diffBlue > threadSold) {
        return false
    }

    return true
}

4
以下所有方法的结果均为0-100的比例。
internal static class ColorDifference
{
    internal enum Method
    {
        Binary, // true or false, 0 is false
        Square,
        Dimensional,
        CIE76
    }

    public static double Calculate(Method method, int argb1, int argb2)
    {
        int[] c1 = ColorConversion.ArgbToArray(argb1);
        int[] c2 = ColorConversion.ArgbToArray(argb2);
        return Calculate(method, c1[1], c2[1], c1[2], c2[2], c1[3], c2[3], c1[0], c2[0]);
    }

    public static double Calculate(Method method, int r1, int r2, int g1, int g2, int b1, int b2, int a1 = -1, int a2 = -1)
    {
        switch (method)
        {
            case Method.Binary:
                return (r1 == r2 && g1 == g2 && b1 == b2 && a1 == a2) ? 0 : 100;
            case Method.CIE76:
                return CalculateCIE76(r1, r2, g1, g2, b1, b2);
            case Method.Dimensional:
                if (a1 == -1 || a2 == -1) return Calculate3D(r1, r2, g1, g2, b1, b2);
                else return Calculate4D(r1, r2, g1, g2, b1, b2, a1, a2);
            case Method.Square:
                return CalculateSquare(r1, r2, g1, g2, b1, b2, a1, a2);
            default:
                throw new InvalidOperationException();
        }
    }

    public static double Calculate(Method method, Color c1, Color c2, bool alpha)
    {
        switch (method)
        {
            case Method.Binary:
                return (c1.R == c2.R && c1.G == c2.G && c1.B == c2.B && (!alpha || c1.A == c2.A)) ? 0 : 100;
            case Method.CIE76:
                if (alpha) throw new InvalidOperationException();
                return CalculateCIE76(c1, c2);
            case Method.Dimensional:
                if (alpha) return Calculate4D(c1, c2);
                else return Calculate3D(c1, c2);
            case Method.Square:
                if (alpha) return CalculateSquareAlpha(c1, c2);
                else return CalculateSquare(c1, c2);
            default:
                throw new InvalidOperationException();
        }
    }

    // A simple idea, based on on a Square
    public static double CalculateSquare(int argb1, int argb2)
    {
        int[] c1 = ColorConversion.ArgbToArray(argb1);
        int[] c2 = ColorConversion.ArgbToArray(argb2);
        return CalculateSquare(c1[1], c2[1], c1[2], c2[2], c1[3], c2[3]);
    }

    public static double CalculateSquare(Color c1, Color c2)
    {
        return CalculateSquare(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B);
    }

    public static double CalculateSquareAlpha(int argb1, int argb2)
    {
        int[] c1 = ColorConversion.ArgbToArray(argb1);
        int[] c2 = ColorConversion.ArgbToArray(argb2);
        return CalculateSquare(c1[1], c2[1], c1[2], c2[2], c1[3], c2[3], c1[0], c2[0]);
    }

    public static double CalculateSquareAlpha(Color c1, Color c2)
    {
        return CalculateSquare(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B, c1.A, c2.A);
    }

    public static double CalculateSquare(int r1, int r2, int g1, int g2, int b1, int b2, int a1 = -1, int a2 = -1)
    {
        if (a1 == -1 || a2 == -1) return (Math.Abs(r1 - r2) + Math.Abs(g1 - g2) + Math.Abs(b1 - b2)) / 7.65;
        else return (Math.Abs(r1 - r2) + Math.Abs(g1 - g2) + Math.Abs(b1 - b2) + Math.Abs(a1 - a2)) / 10.2;
    }

    // from:https://dev59.com/tmox5IYBdhLWcg3wtmg1
    public static double Calculate3D(int argb1, int argb2)
    {
        int[] c1 = ColorConversion.ArgbToArray(argb1);
        int[] c2 = ColorConversion.ArgbToArray(argb2);
        return Calculate3D(c1[1], c2[1], c1[2], c2[2], c1[3], c2[3]);
    }

    public static double Calculate3D(Color c1, Color c2)
    {
        return Calculate3D(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B);
    }

    public static double Calculate3D(int r1, int r2, int g1, int g2, int b1, int b2)
    {
        return Math.Sqrt(Math.Pow(Math.Abs(r1 - r2), 2) + Math.Pow(Math.Abs(g1 - g2), 2) + Math.Pow(Math.Abs(b1 - b2), 2)) / 4.41672955930063709849498817084;
    }

    // Same as above, but made 4D to include alpha channel
    public static double Calculate4D(int argb1, int argb2)
    {
        int[] c1 = ColorConversion.ArgbToArray(argb1);
        int[] c2 = ColorConversion.ArgbToArray(argb2);
        return Calculate4D(c1[1], c2[1], c1[2], c2[2], c1[3], c2[3], c1[0], c2[0]);
    }

    public static double Calculate4D(Color c1, Color c2)
    {
        return Calculate4D(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B, c1.A, c2.A);
    }

    public static double Calculate4D(int r1, int r2, int g1, int g2, int b1, int b2, int a1, int a2)
    {
        return Math.Sqrt(Math.Pow(Math.Abs(r1 - r2), 2) + Math.Pow(Math.Abs(g1 - g2), 2) + Math.Pow(Math.Abs(b1 - b2), 2) + Math.Pow(Math.Abs(a1 - a2), 2)) / 5.1;
    }

    /**
    * Computes the difference between two RGB colors by converting them to the L*a*b scale and
    * comparing them using the CIE76 algorithm { http://en.wikipedia.org/wiki/Color_difference#CIE76}
    */
    public static double CalculateCIE76(int argb1, int argb2)
    {
        return CalculateCIE76(Color.FromArgb(argb1), Color.FromArgb(argb2));
    }

    public static double CalculateCIE76(Color c1, Color c2)
    {
        return CalculateCIE76(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B);
    }

    public static double CalculateCIE76(int r1, int r2, int g1, int g2, int b1, int b2)
    {
        int[] lab1 = ColorConversion.ColorToLab(r1, g1, b1);
        int[] lab2 = ColorConversion.ColorToLab(r2, g2, b2);
        return Math.Sqrt(Math.Pow(lab2[0] - lab1[0], 2) + Math.Pow(lab2[1] - lab1[1], 2) + Math.Pow(lab2[2] - lab1[2], 2)) / 2.55;
    }
}


internal static class ColorConversion
{

    public static int[] ArgbToArray(int argb)
    {
        return new int[] { (argb >> 24), (argb >> 16) & 0xFF, (argb >> 8) & 0xFF, argb & 0xFF };
    }

    public static int[] ColorToLab(int R, int G, int B)
    {
        // http://www.brucelindbloom.com

        double r, g, b, X, Y, Z, fx, fy, fz, xr, yr, zr;
        double Ls, fas, fbs;
        double eps = 216.0f / 24389.0f;
        double k = 24389.0f / 27.0f;

        double Xr = 0.964221f;  // reference white D50
        double Yr = 1.0f;
        double Zr = 0.825211f;

        // RGB to XYZ
        r = R / 255.0f; //R 0..1
        g = G / 255.0f; //G 0..1
        b = B / 255.0f; //B 0..1

        // assuming sRGB (D65)
        if (r <= 0.04045) r = r / 12;
        else r = (float)Math.Pow((r + 0.055) / 1.055, 2.4);

        if (g <= 0.04045) g = g / 12;
        else g = (float)Math.Pow((g + 0.055) / 1.055, 2.4);

        if (b <= 0.04045) b = b / 12;
        else b = (float)Math.Pow((b + 0.055) / 1.055, 2.4);

        X = 0.436052025f * r + 0.385081593f * g + 0.143087414f * b;
        Y = 0.222491598f * r + 0.71688606f * g + 0.060621486f * b;
        Z = 0.013929122f * r + 0.097097002f * g + 0.71418547f * b;

        // XYZ to Lab
        xr = X / Xr;
        yr = Y / Yr;
        zr = Z / Zr;

        if (xr > eps) fx = (float)Math.Pow(xr, 1 / 3.0);
        else fx = (float)((k * xr + 16.0) / 116.0);

        if (yr > eps) fy = (float)Math.Pow(yr, 1 / 3.0);
        else fy = (float)((k * yr + 16.0) / 116.0);

        if (zr > eps) fz = (float)Math.Pow(zr, 1 / 3.0);
        else fz = (float)((k * zr + 16.0) / 116);

        Ls = (116 * fy) - 16;
        fas = 500 * (fx - fy);
        fbs = 200 * (fy - fz);

        int[] lab = new int[3];
        lab[0] = (int)(2.55 * Ls + 0.5);
        lab[1] = (int)(fas + 0.5);
        lab[2] = (int)(fbs + 0.5);
        return lab;
    }
}

4

一个只使用RGB的简单方法是

cR=R1-R2 
cG=G1-G2 
cB=B1-B2 
uR=R1+R2 
distance=cR*cR*(2+uR/256) + cG*cG*4 + cB*cB*(2+(255-uR)/256)

我已经使用这个工具一段时间了,对于大多数情况来说,它的表现足够好。


利用上述公式,距离的取值范围是多少? - Aman Aggarwal
这相当接近欧几里得色差近似值。我猜它是跳过根分量以加快计算速度,因此范围从0到100的3次方。如果你想将其归一化为100,则将距离取平方根的幂次改为 1/3 - Daniel
@阿曼:三个RGB输入范围是0到256,距离范围是0到65536*9(经验发现)。这种方法有效,所以+1。 - Jeff
@Aman:三个 RGB 输入范围为 0 到 256,距离范围为 0 到 65536*9(经实证发现)。这种方法有效,因此+1。 - Jeff
@Daniel:我想你的意思是距离范围从0到589824(65536*9)。为了使其归一化,需要进行1/2次方运算,然后除以768得到距离值(或者类似的运算,但指数是1/2而不是1/3)。 - Jeff
@Jeff,感谢您的纠正,distance/256^2*9将会得到0..1。此外,我建议将/256替换为/255(因为范围是0..255),这样结果就会是0..1,否则它会在大约0.992处达到顶峰。 - Daniel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接