Javascript 根据十六进制颜色获取最接近的颜色名称

Javascript 根据十六进制颜色获取最接近的颜色名称,javascript,performance,colors,levenshtein-distance,Javascript,Performance,Colors,Levenshtein Distance,我试图根据给定的十六进制值获得最匹配的颜色名称。例如,如果我们有十六进制颜色#f00,我们就必须得到colornamered '#ff0000' => 'red' '#000000' => 'black' '#ffff00' => 'yellow' 我目前使用levenshtein距离算法来获得最接近的颜色名称,目前为止效果很好,但有时不如预期 例如: '#0769ad' => 'chocolate' '#00aaee' => 'mediumspringgreen

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

'#ff0000' => 'red'
'#000000' => 'black'
'#ffff00' => 'yellow'
我目前使用levenshtein距离算法来获得最接近的颜色名称,目前为止效果很好,但有时不如预期

例如:

'#0769ad' => 'chocolate'
'#00aaee' => 'mediumspringgreen'
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 = (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);
        });
    };

}());


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

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

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

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);
        });
    };
}());
请注意,只有当
s
t
都是6个字符的彩色十六进制代码时,这才会给出合理的结果

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

例如:

'#0769ad' => 'chocolate'
'#00aaee' => 'mediumspringgreen'
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=(函数(){
功能区(s,t){
如果(!s.length | |!t.length)返回0;
返回距离(s切片(2),t切片(2))+
abs(parseInt(s.slice(0,2,16)-parseInt(t.slice(0,2,16));
}
返回函数(arr、str){
var min=0xffffff;
var最佳,当前,i;
对于(i=0;i

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

对于更相似的颜色,最好使用颜色。如果在排序之前预先计算距离,可以加快排序步骤。此外,我不确定为什么不使用简单的笛卡尔距离计算。(事实上,我想我会转换成一个角坐标空间,并以HSL或HSV为单位计算距离。)我会通过平均每个R、G和B通道上两种颜色之间的差异来计算两种颜色的差异。ex(3,4,5)和(10,14,18)的平均差值为10。我敢打赌,你会发现你有一些问题颜色,可以从列表中删除。我不知道你的问题领域,但也许少就是多。如果我涂上一层绿色,你叫它薄荷绿、浅绿或春绿,那可能没关系。哇,太棒了!感谢到目前为止:-*合理的结果,当s和t都是6个字符的颜色十六进制代码没有问题,我将3位十六进制颜色转换为6位:)顺便说一句:在排序之前预先计算距离会使它更快吗?!需要记住的一件事是,G通道实际上比R和B通道更重要。而且,并非每个级别的步骤在0-255个值中都是相同的,例如:7-2是一个巨大的变化,但132-127相对较小。通过将感知校正(NTSC)灰度差异与上述计算的平均rgb差异求平均值,以此进行筛选。我认为它应该值25%,所以将它添加到rgb和div中,以4而不是3。NTSC灰度计算为((0.29*r)+(0.59*g)+(0.12*b))/3,以防你想知道…@dandavis听起来不错,但我不知道如何实现它。不过,还是要感谢您的心理辅导:)