在Lab色彩空间中的颜色渐变算法

5
假设我有两个Lab颜色空间的颜色:
颜色1:L=81,a=-8,b=74 颜色2:L=64,a=-14,b=3
我想在它们之间生成n个颜色。比如说n=100或者尽可能多的颜色。
我知道RGB和HSV颜色渐变算法。但我想在LAB颜色空间中生成渐变。我不想将颜色转换为HSV或RGB,因为不同的颜色模型会生成不同的渐变。
我找到了一个链接,可以在Lab和其他颜色模型中生成渐变:http://davidjohnstone.net/pages/lch-lab-colour-gradient-picker 我想在Java中做类似的事情,但语言并不重要,我只需要理解背后的逻辑和算法。
我这样做主要是为了将扫描的颜色值与我拥有的5种颜色的图表匹配。所以,我必须首先使用渐变生成所有这些5种颜色之间的颜色,并比较其他颜色以找到最接近的颜色。(为了比较,我使用CIEDE2000 Delta-e方法)。但我想这是次要的问题。
进一步补充我的问题的最后部分,
我想我必须生成一个渐变,因为我想在我拥有的图表序列中找到样本颜色的确切位置。
例如,我有6种绿色阴影(从浅到深),每个对应于0到450毫克之间的特定数字数据,如下所示(带有它们的LAB值):
Color 1: 78, -10, -71 [0 mg]
Color 2: 73,-14,44 [30 mg]
Color 3: 71, -19, 53 [80 mg]
Color 4: 67, -18, 31 [160 mg]
Color 5: 69, -2, 29  [300 mg]
Color 6: 61, -14, 3 [450 mg]

现在我想生成它们之间的所有颜色,并找到扫描颜色的位置并返回 mg 值。 如果我的颜色恰好在 Color 1 和 Color 2 之间,则它将返回 15 mg,否则,如果它更接近 Color 2,则将返回 28.5 mg,依此类推。希望这样可以清楚我要达到的目的。

所以,如果我理解你的意思是,你有一个分段线性的颜色渐变(由线性段的端点定义),你想知道扫描到的颜色大致在这个渐变中的位置,对吗? - Ilmari Karonen
是的,我想在现有的6种颜色之间生成更多的颜色,并找到扫描颜色在渐变中的近似位置,并相应地返回mg值。 - Sarthak Singhal
1个回答

2
要生成两个颜色值之间的渐变,您可以在它们之间进行线性插值。这基本上适用于任何颜色空间,尽管如果两个颜色空间之间的转换不是线性的,则在一个空间中线性插值得到的渐变在另一个空间中不是线性的。因此,在Lab颜色空间中生成渐变与在RGB空间中生成它们完全相同。
(对于像HSV或HSL这样具有“环绕”的色调坐标的颜色空间,可能需要额外小心地选择正确的插值方向;幸运的是,您在此处没有询问这些颜色空间,因此我不需要进入这些细节。)
作为演示,以下是如何在颜色和之间生成一个n个样本的渐变(每个颜色都表示为带有属性LabLabColor对象):
public static LabColor[] makeGradient(LabColor c1, LabColor c2, int n) {
    LabColor gradient = new LabColor[n];
    for (int i = 0; i < n; i++) {
        float alpha = (float)i / (n-1);  // 0.0 <= alpha <= 1.0 
        float L = (1-alpha) * c1.L + alpha * c2.L;
        float a = (1-alpha) * c1.a + alpha * c2.a;
        float b = (1-alpha) * c1.b + alpha * c2.b;
        gradient[i] = new LabColor(L, a, b);
    }
    return gradient;
}

这将返回一个渐变,其中包含n个颜色样本,第一个颜色等于c1,最后一个颜色等于c2,其余颜色在它们之间插值。
然而,根据您问题末尾的备注,我怀疑您实际上并不需要生成任何渐变。相反,要找到与样本最接近的图表颜色,您只需要计算每个图表颜色与样本的感知距离(在Lab色彩空间中,可以通过欧几里得距离很好地近似)并选择最接近的一个:
public static LabColor findNearest(LabColor sample, LabColor[] chart) {
    LabColor nearest = null;
    float minDistanceSquared = Float.POSITIVE_INFINITY;
    for (int i = 0; i < chart.length; i++) {
        float dL = sample.L - chart[i].L;
        float da = sample.a - chart[i].a;
        float db = sample.b - chart[i].b;
        float distanceSquared = dL*dL + da*da + db*db;
        if (distanceSquared < minDistanceSquared) {
            nearest = chart[i];
            minDistanceSquared = distanceSquared;
        }
    }
    return nearest;
}

我已经更新了我的问题,以进一步澄清我要实现的具体目标。 - Sarthak Singhal

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