使用JS在两个值之间的色差/相似度%

时间:2012-11-27 15:00:26

标签: javascript colors

我需要计算两个十六进制颜色值之间的差异,因此输出是一个百分比值。我放弃的第一件事是将十六进制值转换为十进制,因为第一个将比最后一个具有更高的权重。

第二个选项是计算每个RGB值之间的差异,然后将它们全部添加。但是,0, 0, 030, 30, 30之间的差异远远低于0, 0, 090, 0, 0之间的差异。

This question建议使用YUV,但我无法弄清楚如何使用它来确定差异。

此外,this other question有一个很好的公式来计算差异并输出RGB值,但它并不完全存在。

6 个答案:

答案 0 :(得分:8)

问题是你想要一个像3维世界的距离, 但rgb表示根本不直观:'近'颜色可以 “远”的颜色大不相同。

比如两个灰色的c1:(120,120,120)和c2:(150,150,150),现在拿c3:(160,140,​​140)它比c1更接近c2,但是它是紫色的,而对于眼睛来说是深灰色比紫色更接近灰色。

我建议你使用hsv:颜色是由'基色'(色调),饱和度和强度定义的。具有紧密色调的颜色确实非常接近。具有非常不同色调的颜色彼此不相关(探索:黄色和绿色),但可能看起来更接近(非常)低饱和度和(非常)低强度。
(晚上所有颜色都一样。)

由于色调被分为6个块,因此cyl = Math.floor(色调/ 6)为您提供相似度评估的第一步:如果相同的圆柱部分 - >相当接近。 如果它们不属于同一个柱面,如果(h2-h1)很小,它们可能仍然(非常)接近,将它与(1/6)进行比较。如果(h2-h1)> 1/6这可能只是颜色太差了。

然后你可以更精确地使用(s,v)。如果低饱和度/极低饱和度和/或低强度,它们的颜色会更近。

使用支持rgb和hsv的颜色选择器,直到你知道你想要什么作为差值。但请注意,您不能拥有“真正的”相似性度量。

你有一个rgb - > hsv javascript convertor here:http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c

答案 1 :(得分:6)

只需计算Euclidean distance

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

答案 2 :(得分:5)

我发布了一个用于计算三种CIE算法的npm / Bower软件包: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来做到这一点 - 我相信你也可以找到一些特别的东西。

答案 3 :(得分:2)

ColorWiki上颜色比较的第3条规则是“绝不试图通过使用平均因子来转换不同方程式计算的色差”。这是因为在数学上彼此接近的颜色在视觉上并不总是与我们人类相似。

您正在寻找的可能是delta-e,这是一个代表两种颜色之间“距离”的数字。

下面列出了最流行的算法,CIE76(又名CIE 1976或dE76)是最受欢迎的算法。

每个人都以不同的方式处理事物,但在大多数情况下,他们都要求你转换为比RGB更好的(用于比较)颜色模型。

维基百科拥有所有公式:http://en.wikipedia.org/wiki/Color_difference

您可以使用在线颜色计算器检查您的工作:

最后,它不是javascript,而是我开始使用的开源c#库将进行一些转换和计算:https://github.com/THEjoezack/ColorMine

答案 4 :(得分:0)

实施CIE76的JavaScript色差库

https://github.com/garex/nodejs-color-difference

答案 5 :(得分:0)

对于那些只想快速复制/粘贴的人,以下是this repo by antimatter15中的代码(为便于使用,进行了一些调整):

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

enter image description here

上表来自here。上面的代码基于1994年版的DeltaE。