【问题标题】:Color Gradient Algorithm in Lab color spaceLab色彩空间中的色彩梯度算法
【发布时间】:2014-11-23 14:39:07
【问题描述】:

假设我在 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 值。假设我的颜色正好在颜色 1 和颜色 2 之间,那么它会返回 15 毫克,否则如果它更接近颜色 2,它将返回 28.5 毫克,依此类推。

希望这能澄清我想要实现的目标。

【问题讨论】:

  • 所以,如果我理解正确的话,你有一个分段线性颜色渐变(由线性段的端点定义),你想找出扫描颜色大约落在这个渐变的哪个位置,对吗?
  • 是的。我想在现有的 6 种颜色之间生成更多颜色,并在渐变中找到扫描颜色的大致位置并相应地返回 mg 值。

标签: java algorithm colors gradient matching


【解决方案1】:

要在两个颜色值之间生成渐变,您可以在它们之间使用linearly interpolate。这基本上适用于任何颜色空间,尽管如果两个颜色空间之间的变换不是线性的,则通过在一个空间中线性插值获得的梯度在另一个空间中将不是线性的。因此,在 Lab 颜色空间中生成渐变就像在 RGB 空间中生成渐变一样。

(对于像 HSV 或 HSL 这样具有“循环”色相坐标的颜色空间,可能需要额外注意选择正确的插值方向;幸运的是,您在这里没有询问这些颜色空间,所以我不需要详细说明。)


作为一个演示,这里是您如何在颜色 c1c2 之间生成一个 n 样本渐变(每个都给出为具有属性Lab) 的LabColor 对象:

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 ,其余的在它们之间进行插值。


但是,根据您问题末尾的评论,我怀疑您实际上并不 需要 生成任何渐变。相反,要在图表中找到与样本中的颜色最匹配的颜色,您只需计算样本中每种图表颜色的perceptual distance(在 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;
}

【讨论】:

  • 我更新了我的问题,以进一步阐明我想要达到的目标。
猜你喜欢
  • 2018-08-19
  • 2016-12-03
  • 2020-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-25
  • 2013-01-02
相关资源
最近更新 更多