我需要计算两个十六进制颜色值之间的差异,因此输出是百分比值。我放弃的第一件事是将十六进制值转换为十进制值,因为第一个值比最后一个值要高得多。
第二个选项是计算每个 RGB 值之间的差异,然后将它们全部相加。0, 0, 0
但是,和之间的差异30, 30, 30
远小于 和 之间0, 0, 0
的差异90, 0, 0
。
此外,this other question有一个很好的公式来计算差异并输出RGB值,但它并不完全存在。
我需要计算两个十六进制颜色值之间的差异,因此输出是百分比值。我放弃的第一件事是将十六进制值转换为十进制值,因为第一个值比最后一个值要高得多。
第二个选项是计算每个 RGB 值之间的差异,然后将它们全部相加。0, 0, 0
但是,和之间的差异30, 30, 30
远小于 和 之间0, 0, 0
的差异90, 0, 0
。
此外,this other question有一个很好的公式来计算差异并输出RGB值,但它并不完全存在。
对于那些只想快速复制/粘贴的人,这里是antimatter15 的这个 repo的代码(为了便于使用,做了一些调整):
function deltaE(rgbA, rgbB) {
let labA = rgb2lab(rgbA);
let labB = rgb2lab(rgbB);
let deltaL = labA[0] - labB[0];
let deltaA = labA[1] - labB[1];
let deltaB = labA[2] - labB[2];
let c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
let c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
let deltaC = c1 - c2;
let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
let sc = 1.0 + 0.045 * c1;
let sh = 1.0 + 0.015 * c1;
let deltaLKlsl = deltaL / (1.0);
let deltaCkcsc = deltaC / (sc);
let deltaHkhsh = deltaH / (sh);
let i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh;
return i < 0 ? 0 : Math.sqrt(i);
}
function rgb2lab(rgb){
let r = rgb[0] / 255, g = rgb[1] / 255, b = rgb[2] / 255, x, y, z;
r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000;
z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
x = (x > 0.008856) ? Math.pow(x, 1/3) : (7.787 * x) + 16/116;
y = (y > 0.008856) ? Math.pow(y, 1/3) : (7.787 * y) + 16/116;
z = (z > 0.008856) ? Math.pow(z, 1/3) : (7.787 * z) + 16/116;
return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)]
}
要使用它,只需传入两个 rgb 数组:
deltaE([128, 0, 255], [128, 0, 255]); // 0
deltaE([128, 0, 255], [128, 0, 230]); // 3.175
deltaE([128, 0, 255], [128, 0, 230]); // 21.434
deltaE([0, 0, 255], [255, 0, 0]); // 61.24
上表来自这里。上面的代码是基于 DeltaE 的 1994 版本。
问题是你想要像 3 维世界上的距离,但 rgb 表示根本不直观:“近”颜色可能与“远”颜色有很大不同。
以两种灰度 c1 : (120,120,120) 和 c2 : (150,150,150) 和现在的 c3 : (160,140,140) 为例,它比 c1 更接近 c2,但它是紫色的,对于眼睛来说,深灰色更接近比紫色要灰。
我建议您使用 hsv :颜色由“基础”颜色(色调)、饱和度和强度定义。色调相近的颜色确实非常接近。具有非常不同色调的颜色彼此不相关(expl:黄色和绿色),但可能看起来更接近(非常)低饱和度和(非常)低强度。
(晚上所有颜色都一样。)
由于色调分为 6 个块,因此 cyl = Math.floor( hue / 6 ) 为您提供了相似性评估的第一步:如果圆柱体的相同部分 -> 非常接近。如果它们不属于同一个圆柱体,如果 (h2-h1) 很小,它们可能仍然(非常)接近,将其与 (1/6) 进行比较。如果 (h2-h1) > 1/6,这可能只是颜色太不同了。
然后你可以更精确地使用 (s,v)。如果饱和度低/非常低和/或强度低,则颜色更接近。
使用支持 rgb 和 hsv 的颜色选择器,直到你知道你想要什么作为差异值。但请注意,您不能拥有“真正的”相似性度量。
你有一个 rgb --> hsv javascript 转换器:http: //axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
只需计算欧几里得距离:
var c1 = [0, 0, 0],
c2 = [30, 30, 30],
c3 = [90, 0, 0],
distance = function(v1, v2){
var i,
d = 0;
for (i = 0; i < v1.length; i++) {
d += (v1[i] - v2[i])*(v1[i] - v2[i]);
}
return Math.sqrt(d);
};
console.log( distance(c1, c2), distance(c1, c3), distance(c2, c3) );
//will give you 51.96152422706632 90 73.48469228349535
我发布了一个 npm/Bower 包,用于计算三种 CIE 算法:de76、de94 和 de00。
它是公共领域,在 Github 上:
http://zschuessler.github.io/DeltaE/
这是一个快速入门指南:
通过 npm 安装
npm install delta-e
用法
// Include library
var DeltaE = require('delta-e');
// Create two test LAB color objects to compare!
var color1 = {L: 36, A: 60, B: 41};
var color2 = {L: 100, A: 40, B: 90};
// 1976 formula
console.log(DeltaE.getDeltaE76(color1, color2));
// 1994 formula
console.log(DeltaE.getDeltaE94(color1, color2));
// 2000 formula
console.log(DeltaE.getDeltaE00(color1, color2));
您需要转换为 LAB 颜色才能使用此库。d3.js 有一个很好的 API 可以做到这一点——我相信你也可以找到一些临时的东西。
ColorWiki 上颜色比较的第三条规则是“永远不要尝试通过使用平均因子来转换由不同方程计算的颜色差异”。这是因为在数学上彼此接近的颜色并不总是在视觉上与我们人类相似。
您正在寻找的可能是delta-e,它是一个代表两种颜色之间“距离”的数字。
下面列出了最流行的算法,其中 CIE76(又名 CIE 1976 或 dE76)是最流行的。
每个人都以不同的方式处理事情,但在大多数情况下,它们都要求您转换为比 RGB 更好(用于比较)的颜色模型。
维基百科有所有的公式:http ://en.wikipedia.org/wiki/Color_difference
您可以使用在线颜色计算器检查您的工作:
最后,它不是 javascript,但我开始使用一个开源 c# 库来进行一些转换和计算:https ://github.com/THEjoezack/ColorMine