匹配颜色的最佳算法。

问题描述 投票:0回答:6

我有大约 200 种颜色的 RGB 格式数组。我想编写一个程序,它采用任何 RGB 颜色并尝试匹配数组中最“相似”的颜色。

我需要一个“相似”的好定义,尽可能接近人类的感知。

我还想展示一些关于匹配精度的信息。例如黑白:100%,对于色调略有不同的相似颜色:-4%。

我需要使用神经网络吗?有更简单的选择吗?

algorithm graphics language-agnostic color-space
6个回答
39
投票

将所有颜色转换为 CIE Lab 颜色空间 并计算该空间中的距离

deltaE = sqrt(deltaL^2 + deltaA^2 + deltaB^2)

deltaE 最低的颜色在感知上最相似。


4
投票

不,这里不需要神经网络!简单地将 HSL 颜色值视为一个向量,并为该向量定义一个加权模函数,如下所示:

modulus = sqrt(a*H1*H1 + b*S1*S1 + c*L1*L1);

where a,b,c are weights you should decide based on your visual definition of what
creates a bigger difference in perceived color - a 1% change in Hue or a 1%
change in Saturation

我建议你使用 a = b = 0.5 和 c = 1

最后,找出模量的范围,并将相似的颜色定义为模量彼此非常接近的颜色(比如 5%)


1
投票

我还要指出 least squares 方法,只是稍微简单一些。也就是说,你取一个数的差,平方,然后对所有这些平方差求和。


0
投票

我一直在寻找这个东西,但没有找到很多答案,我决定创建这个小图书馆。

https://github.com/sebastienjouhans/c-sharp-colour-utilities


0
投票

我实现这一点的最快方法是将颜色添加到八叉树,然后,就像量化一样,你使用每一位来引导你到最深的子节点。一旦你不能再深入,要么你处于最深的层次(最低位),在这种情况下你已经击中了确切的颜色,要么你需要的下一个子节点不存在——此时你只是需要孩子的钻头最接近您正在寻找的钻头,并且是您最接近的颜色。这比将所有内容转换为 HSL 并返回,或计算每个欧几里德距离要快得多。

这是我在 CodeProject 上的代码:https://www.codeproject.com/tips/1046574/octtree-based-nearest-color-search


0
投票

最近遇到了同样的问题,比较了网上找的各种算法。起初我对使用 CIELAB 色彩空间犹豫不决,因为它很复杂,但它确实没有乍一看那么糟糕。这是比较两个 RGB 值所需的所有代码。

struct CIELAB {
    float L, a, b;
};

float gammaCorrect( float v )
{
    return v <= 0.04045f ? v / 12.92f : powf( (v + 0.055f) / 1.055f, 2.4f );
}

float nonLinearToLinear( float v )
{
    return v > 0.008856f ? cbrtf( v ) : 7.787f * v + 16.0f / 116.0f;
}

CIELAB RGBToCIELAB( int R, int G, int B )
{
    float red = 100.0f * gammaCorrect( R / 255.0f );
    float green = 100.0f * gammaCorrect( G / 255.0f );
    float blue = 100.0f * gammaCorrect( B / 255.0f );

    float xr = nonLinearToLinear( (red * 0.4124564f + green * 0.3575761f + blue * 0.1804375f) / 95.047f );
    float yr = nonLinearToLinear( (red * 0.2126729f + green * 0.7151522f + blue * 0.0721750f) / 100.000f );
    float zr = nonLinearToLinear( (red * 0.0193339f + green * 0.1191920f + blue * 0.9503041f) / 108.883f );

    return { 116.0f * yr - 16.0f, 500.0f * (xr - yr), 200.0f * (yr - zr) };
}

float similarity( int R0, int G0, int B0, int R1, int G1, int B1 )
{
    CIELAB lab0 = RGBToCIELAB( R0, G0, B0 );
    CIELAB lab1 = RGBToCIELAB( R1, G1, B1 );
    float dL = lab0.L - lab1.L;
    float da = lab0.a - lab1.a;
    float db = lab0.b - lab1.b;
    return dL*dL + da*da + db*db;
}

对于 similarity() 函数,结果越低匹配越好。为了提高效率,请将 RGB 颜色列表预先转换为 CIELAB 空间。

如果需要更简单的算法,维基百科的Color difference 页面有一个非常有效的算法。您可以使用整数运算来实现它,如果只比较相似性,则可以跳过平方根计算。

int similarity( int R0, int G0, int B0, int R1, int G1, int B1 )
{
    int dr = R0 - R1;
    int dg = G0 - G1;
    int db = B0 - B1;
    int redsum = R0 + R1;
    return (1024 + redsum) * dr*dr + 2048 * dg*dg + (1534 - redsum) * db*db;
}

计算不会超过 32 位有符号整数。

我发现这种匹配明显不如 CIELAB 空间中的匹配,但计算是微不足道的。

我也尝试在 HSV 颜色空间中进行匹配,但对于某些颜色对没有得到好的结果。例如,纯白色和纯黑色(两种颜色可能完全不同)可以具有相同的色调和饱和度,因此可能比您想要的更匹配。

© www.soinside.com 2019 - 2024. All rights reserved.