【问题标题】:PHP convert 24-bit colors to 4-bitPHP 将 24 位颜色转换为 4 位
【发布时间】:2014-12-01 06:22:17
【问题描述】:

背景,我正在将图像转换为 ascii 艺术。这可以完美地工作,甚至可以使用 24 位颜色,将颜色转换为正确的 rgb 值。但是,我现在想用 4 位调色板而不是 24 位来渲染 ascii 艺术。

如何使用 PHP 将 24 位颜色转换为 4 位?

更具体地说,我有标准的 IRC 调色板,我需要将任何给定的十六进制或 RGB 值转换为该调色板。转换为 4 位颜色时,颜色应尽可能匹配。

我对此的其他想法是将图像本身转换为 4 位调色板(使用 GD,这是我现在用来读取颜色的方法),然后再尝试从中获取颜色。另一个想法可能是为以下每种颜色定义一个颜色范围,并检查给定的 24 位颜色是否在该范围内,但是我不知道如何将所有颜色的范围放入该调色板。

【问题讨论】:

    标签: php colors gd


    【解决方案1】:

    imagetruecolortopalette 允许您减少颜色,但结果可能会有很大差异,我不知道是否有办法正确“映射”颜色或指定调色板。

    测试图像(24 位):

    减少到 4 位(无抖动):

    $img = imagecreatefrompng('Bliss.png');
    imagetruecolortopalette($img, false, 16);
    imagepng($img, 'Bliss2.png');
    

    减少到 4 位(带抖动):

    $img = imagecreatefrompng('Bliss.png');
    imagetruecolortopalette($img, true, 16);
    imagepng($img, 'Bliss3.png');
    

    如您所见,结果远非完美。但也许这对你来说是一个好的开始。

    【讨论】:

      【解决方案2】:

      最后,尽管围绕 imagemagick 提出了很好的建议,但我还是找到了一个使用直接 php 的好解决方案。我能够通过使用 delta E 2000 和在 github 上找到的 php-color-difference 库的修改版本来计算最接近的颜色,这是我的 fork:https://github.com/nalipaz/php-color-difference

      相关的例子是:

      <?php
      include('lib/color_difference.class.php');
      
      $palette = array(
        '00' => array(255, 255, 255),
        '01' => array(0, 0, 0),
        '02' => array(0, 0, 139),
        '03' => array(0, 128, 0),
        '04' => array(255, 0, 0),
        '05' => array(139, 0, 0),
        '06' => array(128, 0, 128),
        '07' => array(255, 165, 0),
        '08' => array(255, 255, 0),
        '09' => array(50, 205, 50),
        '10' => array(0, 128, 128),
        '11' => array(173, 216, 230),
        '12' => array(0, 0, 255),
        '13' => array(255, 105, 180),
        '14' => array(128, 128, 128),
        '15' => array(211, 211, 211),
      );
      
      $color_rgb = array(255, 255, 128);
      $color_delta_e = new color_difference($color_rgb);
      $match_index = $color_delta_e->getClosestMatch($palette);
      $color = $palette[$match_index];
      

      我对这个解决方案和较少的开销非常满意。谢谢大家的建议。

      【讨论】:

        【解决方案3】:

        我认为 ImageMagick(或 GraphicsMagick)可以通过 -depth 选项来做到这一点。这里有一个讨论:http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=15395

        更新:我应该补充一点,ImageMagick 不是 PHP 库,但是在 http://pecl.php.net/package/imagick 有一个 PECL 包装器(imagick)。

        【讨论】:

        • ImageMagick 可以轻松成为一项要求。我猜我需要在使用此权利之前将任何 jpe?g 和 gif 转换为 png?
        • 我认为 -depth 选项适用于各种格式 - 请参阅 imagemagick.org/script/command-line-options.php#depth
        • 研究不断变化的深度。这可能会有所帮助,但这并不能说明我需要用上述调色板中的颜色替换颜色。生成的图像只需要是上述调色板中的颜色。也许如果我通过深度变化减少到 16 种颜色,然后用上面的颜色替换 16 种颜色中的每一种,那么它可能会起作用。但是,我需要研究颜色的替换,并将上述每种颜色与结果图像中的合理颜色进行匹配。
        【解决方案4】:

        我认为您需要使用remap 将图像中的颜色映射到样本中的调色板。我在命令行中这样做:

        convert image.jpg -remap palette.jpg out.jpg
        

        您可能想要也可能不想要 dither 选项 - 看看吧。

        原图在这里:

        这是我的palette.jpg(你只需要一个非常小的图像,这太大了——我很快就会解决这个问题)

        和结果

        您还可以使用 ImageMagick 根据您想要的颜色创建调色板。我手工编写了以下代码,并没有过多关注,因此您需要先检查此处的 RGB 值,然后再假设它们是正确的:

        #/bin/bash
        cat<<EOF | convert txt:- palette.png
        # ImageMagick pixel enumeration: 8,2,256,rgb
        0,0: (255,255,255)
        1,0: (0,0,0)
        2,0: (0,0,255)
        3,0: (255,255,0)
        4,0: (255,0,0)
        5,0: (128,128,128)
        6,0: (255,105,180)
        7,0: (173,216,230)
        0,1: (50,205,50)
        1,1: (139,0,0)
        2,1: (255,165,0)
        3,1: (128,0,128)
        4,1: (0,0,139)
        5,1: (0,128,128)
        6,1: (0,128,0)
        7,1: (211,211,211)
        EOF
        

        基本上,上面的脚本将 RGB 值作为文本提供给 ImageMagick,并要求它制作如下所示的 8x2 小图像:

        然后,您可以将此调色板与您的 remap 操作一起使用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-11-25
          • 1970-01-01
          • 1970-01-01
          • 2011-07-30
          • 2011-08-23
          • 1970-01-01
          • 2012-07-17
          • 1970-01-01
          相关资源
          最近更新 更多