假设我在 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 mg 之间的特定数字数据,如下所示(带有它们的 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 毫克,依此类推。
希望这能澄清我想要实现的目标。
要在两个颜色值之间生成渐变,只需在它们之间进行线性插值。 这基本上适用于任何颜色空间,尽管如果两个颜色空间之间的转换不是线性的,则在一个空间中线性插值获得的梯度在另一个空间中将不是线性的。 因此,在 Lab 色彩空间中生成渐变与在 RGB 空间中生成渐变完全相同。
(对于像HSV或HSL这样的色调坐标"循环"的颜色空间,可能需要格外小心地选择正确的插值方向;幸运的是,你在这里没有问这些颜色空间,所以我不需要详细介绍。
作为演示,下面介绍如何在颜色 c1 和 c2 之间生成 n 样本渐变(每个颜色都作为属性为 L
、a
和 b
的 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,其余颜色在它们之间插值。
但是,根据您问题末尾的评论,我怀疑您实际上不需要生成任何梯度。 相反,要找到图表中与样本中最匹配的颜色,您只需计算每种图表颜色与样本的感知距离(在 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;
}