【问题标题】:Sorting by Color按颜色排序
【发布时间】:2010-11-18 15:54:36
【问题描述】:

我有一长串(1000 多种)十六进制颜色,按一般颜色类别(红色、橙色、蓝色等)分类。当我显示每个类别中的颜色列表时,我需要按阴影顺序显示它们。即先是浅红色,最后是深红色。

执行此操作的算法是什么? (谷歌搜索失败了)

【问题讨论】:

    标签: php sorting colors


    【解决方案1】:

    我知道这个问题很老,但我没有找到解决这个问题的好方法,所以我做了一些调查,并想分享我为假设的未来谷歌员工所做的事情。

    首先,转换为 HSL 是个好主意。但是,当您的颜色没有“分类”时,仅按色调或亮度排序并不能完全解决问题。

    给定一个看起来像这样的数组:

    $colors = [
                [ 'color' => '#FDD4CD'],
                [ 'color' => '#AE3B3B'],
                [ 'color' => '#DB62A0'],
                ...
              ]
    

    首先我们将所有十六进制颜色转换为 HSL

    foreach ($colors as &$color) {
           $color['hsl'] = hexToHsl($color['color']);
    }
    
    
    /**
     * Convert a hexadecimal color in RGB
     * @param string $hex
     * @return array
     */
    function hexToHsl($hex){
        list($r, $g, $b) = sscanf($hex, "#%02x%02x%02x");
        return rgbToHsl($r, $g, $b);
    }
    
    /**
     * Convert a RGB color in its HSL value
     * @param int $r red
     * @param int $g green
     * @param int $b blue
     * @return array
     */
    function rgbToHsl($r, $g, $b)
    {
        $r /= 255;
        $g /= 255;
        $b /= 255;
    
        $max = max($r, $g, $b);
        $min = min($r, $g, $b);
    
        $h = 0;
        $l = ($max + $min) / 2;
        $d = $max - $min;
    
        if ($d == 0) {
            $h = $s = 0; // achromatic
        } else {
            $s = $d / (1 - abs(2 * $l - 1));
    
            switch ($max) {
                case $r:
                    $h = 60 * fmod((($g - $b) / $d), 6);
                    if ($b > $g) {
                        $h += 360;
                    }
                    break;
    
                case $g:
                    $h = 60 * (($b - $r) / $d + 2);
                    break;
    
                case $b:
                    $h = 60 * (($r - $g) / $d + 4);
                    break;
            }
        }
        return array('h' => round($h, 2), 's' => round($s, 2), 'l' => round($l, 2));
    }
    

    然后对颜色进行排序

    我们比较:

    • 如果它们处于相同的“间隔”(This help to understand why I choose 30°),它们的色调。所以我们只有在两者都在 [0-30]、[30-60]、[60-90]、...时才比较色调。
    • 如果不在同一区间,则按亮度排序,如果两者共享相同的亮度,则按饱和度排序。

    所以:

    usort($colors, function ($a, $b) {
        //Compare the hue when they are in the same "range"
        if(!huesAreinSameInterval($a['hsl']['h'],$b['hsl']['h'])){
           if ($a['hsl']['h'] < $b['hsl']['h'])
               return -1;
           if ($a['hsl']['h'] > $b['hsl']['h'])
               return 1;
        }
        if ($a['hsl']['l'] < $b['hsl']['l'])
            return 1;
        if ($a['hsl']['l'] > $b['hsl']['l'])
            return -1;
        if ($a['hsl']['s'] < $b['hsl']['s'])
             return -1;
        if ($a['hsl']['s'] > $b['hsl']['s'])
              return 1;
        return 0;
     });
    
    /**
     * Check if two hues are in the same given interval
     * @param float $hue1
     * @param float $hue2
     * @param int $interval
     * @return bool
     */
    function huesAreinSameInterval($hue1, $hue2, $interval = 30){
        return (round(($hue1 / $interval), 0, PHP_ROUND_HALF_DOWN) === round(($hue2 / $interval), 0, PHP_ROUND_HALF_DOWN));
    }
    

    www.brandonheyer.com找到的rgbToHsl

    stackoverflow找到的hexToRgb

    【讨论】:

      【解决方案2】:

      将颜色从 RGB 转换为 HSV or HSL 比例,然后按值或亮度对其进行排序。亮度可能会更好,因为它可以更好地捕捉“褪色”的颜色,例如粉红色->红色->深红色。

      【讨论】:

      • 这里有一个 PHP 实现(当心 DaniWeb 弹出窗口)我不能保证它的质量。
      • 感谢您的链接,我发现这个很好用:phpclasses.org/browse/package/4598.html 现在正在进行排序,将报告结果。感谢您的帮助!
      • 好的,最后。使用此类将十六进制转换为其他版本。非常有用:phpclasses.org/browse/package/4598.html 我尝试对 HSV 进行排序,但这似乎不如对 RGB 值排序正确。然而,这正是我想要的。非常感谢大家的帮助!
      【解决方案3】:

      如果将颜色转换为 HSV 空间,则可能会先按色调排序,然后按值排序。

      色调将决定颜色的“类别”——即:红色、蓝色、绿色等。

      数值和饱和度会影响最终颜色的“亮度”。不过,您可能需要进行一些实验才能获得理想的排序。

      【讨论】:

        猜你喜欢
        • 2011-09-02
        • 1970-01-01
        • 2013-04-16
        • 2012-07-24
        • 2015-09-03
        • 2011-10-23
        • 2016-09-25
        • 1970-01-01
        • 2014-11-07
        相关资源
        最近更新 更多