【问题标题】:Get the closest color name depending on an hex-color根据十六进制颜色获取最接近的颜色名称
【发布时间】:2013-06-18 17:53:23
【问题描述】:

我尝试根据给定的十六进制值获取最匹配的颜色名称。例如,如果我们有十六进制颜色#f00,我们必须得到颜色名称red

'#ff0000' => 'red'
'#000000' => 'black'
'#ffff00' => 'yellow'

我目前使用 levenshtein-distance 算法来获取最接近的颜色名称,目前效果很好,但有时不如预期。

例如:

'#0769ad' => 'chocolate'
'#00aaee' => 'mediumspringgreen'

那么有什么想法可以让结果更接近吗?

这是我为获得最接近的颜色所做的:

Array.closest = (function () {

    // http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#JavaScript
    function levDist(s, t) {
        if (!s.length) return t.length;
        if (!t.length) return s.length;

        return Math.min(
            levDist(s.substring(1), t) + 1,
            levDist(t.substring(1), s) + 1,
            levDist(s.substring(1), t.substring(1)) + (s[0] !== t[0] ? 1 : 0)
        );
    }

    return function (arr, str) {
        // http://stackoverflow.com/q/11919065/1250044#comment16113902_11919065
        return arr.sort(function (a, b) {
            return levDist(a, str) - levDist(b, str);
        });
    };

}());

http://jsfiddle.net/ARTsinn/JUZVd/2/

另一件事是性能!似乎有一个非常大的问题使得这非常慢(是算法吗?)。

【问题讨论】:

  • 对于更相似的颜色,最好使用HSL颜色。
  • 如果您在排序前预先计算距离,您可以使排序步骤加快 很多
  • 我也不确定你为什么不使用简单的笛卡尔距离计算。 (实际上我想我会转换为角坐标空间并在 HSL 或 HSV 燕鸥中计算距离。)
  • 我将通过平均每个 R、G 和 B 通道上两种颜色的差异来计算两种颜色的差异。 ex (3,4,5) 和 (10,14,18) 的平均差异为 10。
  • 我敢打赌,您会发现您有一些问题颜色,您可以将其排除在列表之外。我不知道您的问题域,但也许少即是多。如果我提出一种绿色,而你称它为薄荷绿、浅绿或春绿,那可能并不重要。

标签: javascript performance colors levenshtein-distance


【解决方案1】:

Levenshtein 距离在这里并不合适,因为它会逐个字符比较是否相等。您需要分别检查每种颜色,并且您希望79 更接近80 而不是00

以下似乎更接近您想要的,只需对您的代码进行少量更改:

Array.closest = (function () {
    function dist(s, t) {
        if (!s.length || !t.length) return 0;
        return dist(s.slice(2), t.slice(2)) +
            Math.abs(parseInt(s.slice(0, 2), 16) - parseInt(t.slice(0, 2), 16));
    }

    return function (arr, str) {
        return arr.sort(function (a, b) {
            return dist(a, str) - dist(b, str);
        });
    };
}());

请注意,只有当 st 都是 6 个字符的颜色十六进制代码时,这才会给出合理的结果。

您的代码效率低下,因为您不需要对整个数组进行排序以获得最接近的颜色。相反,您应该只循环遍历数组并跟踪最短距离。

例如:

Array.closest = (function () {
    function dist(s, t) {
        if (!s.length || !t.length) return 0;
        return dist(s.slice(2), t.slice(2)) +
            Math.abs(parseInt(s.slice(0, 2), 16) - parseInt(t.slice(0, 2), 16));
    }

    return function (arr, str) {
        var min = 0xffffff;
        var best, current, i;
        for (i = 0; i < arr.length; i++) {
            current = dist(arr[i], str)
            if (current < min) {
                min = current
                best = arr[i];
            }
        }
        return best;
    };
}());

请注意,在此更改之后,Array.closest() 将返回单个值而不是数组,因此您需要在代码中进一步删除 [0]

【讨论】:

  • 哇,太好了!到目前为止感谢:-* 当 s 和 t 都是 6 字符颜色十六进制代码时的合理结果 没问题我将 3 位十六进制颜色转换为 6 个 :)
  • 顺便说一句:Pointy mentioned 在排序之前预先计算距离可以让它更快?!
  • 要记住的一点是,G 通道实际上比 R 和 B 通道更重要。此外,在 0-255 值的每个值上,并非每个级别步骤都相同,例如:7 -2 是一个巨大的变化,但 132-127 相对较小。通过将感知校正 (NTSC) 灰度差异与上面计算的 avg rgb 差异进行平均来屏蔽这一点。我认为它应该值 25%,所以将它添加到 rgb 和 div 中,而不是 3。NTSC 灰度计算为 ((0.29*r)+(0.59*g)+(0.12*b)) / 3 in如果您想知道...
  • @dandavis 听起来不错,但我不知道如何实现。不过,还是谢谢你的指点 :)
猜你喜欢
  • 2012-04-06
  • 1970-01-01
  • 2015-04-12
  • 1970-01-01
  • 1970-01-01
  • 2012-08-08
  • 2012-07-29
  • 2012-11-04
  • 1970-01-01
相关资源
最近更新 更多