如何将RGB颜色转换为最接近的匹配8位颜色?

时间:2012-10-09 20:08:26

标签: algorithm colors rgb

我有一个应用程序可以索引视频中出现的前16种颜色。

我正在尝试编写另一个允许用户选择颜色的应用程序,然后应用程序会找到此颜色出现的所有视频。

问题在于,由于每个视频仅索引16种颜色,因此用户选择RGB颜色。这种颜色被索引的概率非常低,因此我的应用程序几乎总是没有返回结果。

我想到了一种可以让它工作的方法 - 我可以索引视频中出现的颜色并将它们转换为最接近的8位颜色。

然后,当用户选择RGB颜色时,我可以将用户选择转换为相同的8位最接近的颜色。

这样我总能有比赛。

我现在唯一的主要问题是如何将RGB颜色转换为最接近的8位颜色?

7 个答案:

答案 0 :(得分:8)

要转换为Web安全调色板,您需要将每个r,g,b组件的范围从0-255转换为0-5并将它们组合:

color = (r*6/256)*36 + (g*6/256)*6 + (b*6/256)

答案 1 :(得分:6)

您需要做的是将RGB转换为HSB(色调饱和度亮度)值。 HSB是3个字节,就像RGB一样,区别在于HSB值可以比RGB更容易比较。

您的下一步是决定“重要性”加权。例如,如果您关心的只是“颜色/色调”,而不是饱和度或亮度,那么您可以丢弃S和B字节,只使用颜色字节。

如果是我和我被限制为8位,我将使用4位颜色信息(16种不同颜色),3位饱和度(8种不同值)和1位亮度信息(亮或暗)。

本文介绍如何在Java中执行HSB:

http://java.sys-con.com/node/43559

本文的源代码在Java中有一个RGB到HSB转换器。

答案 2 :(得分:2)

一种可能性是简单地将24位颜色缩小为8位颜色空间。正如cHao所提到的,你可以使用RRRGGGBB作为你的8位数字。然后,可以通过简单的缩放算法计算每个颜色分量,例如:

byte red = (originalColor.red * 8) / 256;
byte green = (originalColor.green * 8) / 256;
byte blue = (originalColor.blue * 4) / 256;

8,4和254是每个颜色分量中可能值的数量。在原始的24位颜色中,红色,绿色和蓝色都可以有256个可能的值,因此这是缩放方程的除数。在示例8位颜色中,红色和绿色各3位(8个可能值),蓝色2位(4个可能值)。

获得这三个组件后,可以将它们与一些简单的位移算术结合起来:

byte eightBitColor = (red << 5) | (green << 2) | blue;

然后您可以简单地比较这些8位颜色。它们的分辨率大大降低可能对你有所帮助。

或者,您可以执行类似Tyler建议的操作,并首先转换为HSB或HSV,并仅比较色调(取决于您是否需要亮度和饱和度信息)。根据您的目标,这实际上可能是一个更理想的解决方案。

编辑:修改缩放算法以修复Mark Ransom指出的缺点。

答案 3 :(得分:1)

这是几年前我发现的非常有用的Python脚本。所有功劳归于 Micah Elliott

使用方法:

  1. 复制整个代码,并使用所需名称创建一个.py文件。
  2. 程序可以转换(Hex-> RGB)和(RGB-> Hex)
  3. 运行程序并进行如下辩论:python file.py 9CE445获得最接近的8位颜色值,而python file.py 204获得确切的十六进制值。

    """ Convert values between RGB hex codes and xterm-256 color codes.
    Nice long listing of all 256 colors and their codes. Useful for
    developing console color themes, or even script output schemes.
    Resources:
    * http://en.wikipedia.org/wiki/8-bit_color
    * http://en.wikipedia.org/wiki/ANSI_escape_code
    * /usr/share/X11/rgb.txt
    I'm not sure where this script was inspired from. I think I must have
    written it from scratch, though it's been several years now.
    """
    
    __author__    = 'Micah Elliott http://MicahElliott.com'
    __version__   = '0.1'
    __copyright__ = 'Copyright (C) 2011 Micah Elliott.  All rights reserved.'
    __license__   = 'WTFPL http://sam.zoy.org/wtfpl/'
    
    #---------------------------------------------------------------------
    
    import sys, re
    
    CLUT = [  # color look-up table
    #    8-bit, RGB hex
    
        # Primary 3-bit (8 colors). Unique representation!
        ('00',  '000000'),
        ('01',  '800000'),
        ('02',  '008000'),
        ('03',  '808000'),
        ('04',  '000080'),
        ('05',  '800080'),
        ('06',  '008080'),
        ('07',  'c0c0c0'),
    
        # Equivalent "bright" versions of original 8 colors.
        ('08',  '808080'),
        ('09',  'ff0000'),
        ('10',  '00ff00'),
        ('11',  'ffff00'),
        ('12',  '0000ff'),
        ('13',  'ff00ff'),
        ('14',  '00ffff'),
        ('15',  'ffffff'),
    
        # Strictly ascending.
        ('16',  '000000'),
        ('17',  '00005f'),
        ('18',  '000087'),
        ('19',  '0000af'),
        ('20',  '0000d7'),
        ('21',  '0000ff'),
        ('22',  '005f00'),
        ('23',  '005f5f'),
        ('24',  '005f87'),
        ('25',  '005faf'),
        ('26',  '005fd7'),
        ('27',  '005fff'),
        ('28',  '008700'),
        ('29',  '00875f'),
        ('30',  '008787'),
        ('31',  '0087af'),
        ('32',  '0087d7'),
        ('33',  '0087ff'),
        ('34',  '00af00'),
        ('35',  '00af5f'),
        ('36',  '00af87'),
        ('37',  '00afaf'),
        ('38',  '00afd7'),
        ('39',  '00afff'),
        ('40',  '00d700'),
        ('41',  '00d75f'),
        ('42',  '00d787'),
        ('43',  '00d7af'),
        ('44',  '00d7d7'),
        ('45',  '00d7ff'),
        ('46',  '00ff00'),
        ('47',  '00ff5f'),
        ('48',  '00ff87'),
        ('49',  '00ffaf'),
        ('50',  '00ffd7'),
        ('51',  '00ffff'),
        ('52',  '5f0000'),
        ('53',  '5f005f'),
        ('54',  '5f0087'),
        ('55',  '5f00af'),
        ('56',  '5f00d7'),
        ('57',  '5f00ff'),
        ('58',  '5f5f00'),
        ('59',  '5f5f5f'),
        ('60',  '5f5f87'),
        ('61',  '5f5faf'),
        ('62',  '5f5fd7'),
        ('63',  '5f5fff'),
        ('64',  '5f8700'),
        ('65',  '5f875f'),
        ('66',  '5f8787'),
        ('67',  '5f87af'),
        ('68',  '5f87d7'),
        ('69',  '5f87ff'),
        ('70',  '5faf00'),
        ('71',  '5faf5f'),
        ('72',  '5faf87'),
        ('73',  '5fafaf'),
        ('74',  '5fafd7'),
        ('75',  '5fafff'),
        ('76',  '5fd700'),
        ('77',  '5fd75f'),
        ('78',  '5fd787'),
        ('79',  '5fd7af'),
        ('80',  '5fd7d7'),
        ('81',  '5fd7ff'),
        ('82',  '5fff00'),
        ('83',  '5fff5f'),
        ('84',  '5fff87'),
        ('85',  '5fffaf'),
        ('86',  '5fffd7'),
        ('87',  '5fffff'),
        ('88',  '870000'),
        ('89',  '87005f'),
        ('90',  '870087'),
        ('91',  '8700af'),
        ('92',  '8700d7'),
        ('93',  '8700ff'),
        ('94',  '875f00'),
        ('95',  '875f5f'),
        ('96',  '875f87'),
        ('97',  '875faf'),
        ('98',  '875fd7'),
        ('99',  '875fff'),
        ('100', '878700'),
        ('101', '87875f'),
        ('102', '878787'),
        ('103', '8787af'),
        ('104', '8787d7'),
        ('105', '8787ff'),
        ('106', '87af00'),
        ('107', '87af5f'),
        ('108', '87af87'),
        ('109', '87afaf'),
        ('110', '87afd7'),
        ('111', '87afff'),
        ('112', '87d700'),
        ('113', '87d75f'),
        ('114', '87d787'),
        ('115', '87d7af'),
        ('116', '87d7d7'),
        ('117', '87d7ff'),
        ('118', '87ff00'),
        ('119', '87ff5f'),
        ('120', '87ff87'),
        ('121', '87ffaf'),
        ('122', '87ffd7'),
        ('123', '87ffff'),
        ('124', 'af0000'),
        ('125', 'af005f'),
        ('126', 'af0087'),
        ('127', 'af00af'),
        ('128', 'af00d7'),
        ('129', 'af00ff'),
        ('130', 'af5f00'),
        ('131', 'af5f5f'),
        ('132', 'af5f87'),
        ('133', 'af5faf'),
        ('134', 'af5fd7'),
        ('135', 'af5fff'),
        ('136', 'af8700'),
        ('137', 'af875f'),
        ('138', 'af8787'),
        ('139', 'af87af'),
        ('140', 'af87d7'),
        ('141', 'af87ff'),
        ('142', 'afaf00'),
        ('143', 'afaf5f'),
        ('144', 'afaf87'),
        ('145', 'afafaf'),
        ('146', 'afafd7'),
        ('147', 'afafff'),
        ('148', 'afd700'),
        ('149', 'afd75f'),
        ('150', 'afd787'),
        ('151', 'afd7af'),
        ('152', 'afd7d7'),
        ('153', 'afd7ff'),
        ('154', 'afff00'),
        ('155', 'afff5f'),
        ('156', 'afff87'),
        ('157', 'afffaf'),
        ('158', 'afffd7'),
        ('159', 'afffff'),
        ('160', 'd70000'),
        ('161', 'd7005f'),
        ('162', 'd70087'),
        ('163', 'd700af'),
        ('164', 'd700d7'),
        ('165', 'd700ff'),
        ('166', 'd75f00'),
        ('167', 'd75f5f'),
        ('168', 'd75f87'),
        ('169', 'd75faf'),
        ('170', 'd75fd7'),
        ('171', 'd75fff'),
        ('172', 'd78700'),
        ('173', 'd7875f'),
        ('174', 'd78787'),
        ('175', 'd787af'),
        ('176', 'd787d7'),
        ('177', 'd787ff'),
        ('178', 'd7af00'),
        ('179', 'd7af5f'),
        ('180', 'd7af87'),
        ('181', 'd7afaf'),
        ('182', 'd7afd7'),
        ('183', 'd7afff'),
        ('184', 'd7d700'),
        ('185', 'd7d75f'),
        ('186', 'd7d787'),
        ('187', 'd7d7af'),
        ('188', 'd7d7d7'),
        ('189', 'd7d7ff'),
        ('190', 'd7ff00'),
        ('191', 'd7ff5f'),
        ('192', 'd7ff87'),
        ('193', 'd7ffaf'),
        ('194', 'd7ffd7'),
        ('195', 'd7ffff'),
        ('196', 'ff0000'),
        ('197', 'ff005f'),
        ('198', 'ff0087'),
        ('199', 'ff00af'),
        ('200', 'ff00d7'),
        ('201', 'ff00ff'),
        ('202', 'ff5f00'),
        ('203', 'ff5f5f'),
        ('204', 'ff5f87'),
        ('205', 'ff5faf'),
        ('206', 'ff5fd7'),
        ('207', 'ff5fff'),
        ('208', 'ff8700'),
        ('209', 'ff875f'),
        ('210', 'ff8787'),
        ('211', 'ff87af'),
        ('212', 'ff87d7'),
        ('213', 'ff87ff'),
        ('214', 'ffaf00'),
        ('215', 'ffaf5f'),
        ('216', 'ffaf87'),
        ('217', 'ffafaf'),
        ('218', 'ffafd7'),
        ('219', 'ffafff'),
        ('220', 'ffd700'),
        ('221', 'ffd75f'),
        ('222', 'ffd787'),
        ('223', 'ffd7af'),
        ('224', 'ffd7d7'),
        ('225', 'ffd7ff'),
        ('226', 'ffff00'),
        ('227', 'ffff5f'),
        ('228', 'ffff87'),
        ('229', 'ffffaf'),
        ('230', 'ffffd7'),
        ('231', 'ffffff'),
    
        # Gray-scale range.
        ('232', '080808'),
        ('233', '121212'),
        ('234', '1c1c1c'),
        ('235', '262626'),
        ('236', '303030'),
        ('237', '3a3a3a'),
        ('238', '444444'),
        ('239', '4e4e4e'),
        ('240', '585858'),
        ('241', '626262'),
        ('242', '6c6c6c'),
        ('243', '767676'),
        ('244', '808080'),
        ('245', '8a8a8a'),
        ('246', '949494'),
        ('247', '9e9e9e'),
        ('248', 'a8a8a8'),
        ('249', 'b2b2b2'),
        ('250', 'bcbcbc'),
        ('251', 'c6c6c6'),
        ('252', 'd0d0d0'),
        ('253', 'dadada'),
        ('254', 'e4e4e4'),
        ('255', 'eeeeee'),
    ]
    
    def _str2hex(hexstr):
        return int(hexstr, 16)
    
    def _strip_hash(rgb):
        # Strip leading `#` if exists.
        if rgb.startswith('#'):
            rgb = rgb.lstrip('#')
        return rgb
    
    def _create_dicts():
        short2rgb_dict = dict(CLUT)
        rgb2short_dict = {}
        for k, v in short2rgb_dict.items():
            rgb2short_dict[v] = k
        return rgb2short_dict, short2rgb_dict
    
    def short2rgb(short):
        return SHORT2RGB_DICT[short]
    
    def print_all():
        """ Print all 256 xterm color codes.
        """
        for short, rgb in CLUT:
            sys.stdout.write('\033[48;5;%sm%s:%s' % (short, short, rgb))
            sys.stdout.write("\033[0m  ")
            sys.stdout.write('\033[38;5;%sm%s:%s' % (short, short, rgb))
            sys.stdout.write("\033[0m\n")
        print ("Printed all codes.")
        print ("You can translate a hex or 0-255 code by providing an argument.")
    
    def rgb2short(rgb):
        """ Find the closest xterm-256 approximation to the given RGB value.
        @param rgb: Hex code representing an RGB value, eg, 'abcdef'
        @returns: String between 0 and 255, compatible with xterm.
        >>> rgb2short('123456')
        ('23', '005f5f')
        >>> rgb2short('ffffff')
        ('231', 'ffffff')
        >>> rgb2short('0DADD6') # vimeo logo
        ('38', '00afd7')
        >>> rgb2short('3D3D3D')
        ('237', '3a3a3a')
        >>> rgb2short('070707')
        ('232', '080808')
        """
        rgb = _strip_hash(rgb)
        # Break 6-char RGB code into 3 integer vals.
        parts = [ int(h, 16) for h in re.split(r'(..)(..)(..)', rgb)[1:4] ]
    
        incs = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
    
        if parts[0] == parts[1] == parts[2]:
            gs_incs = range(0x08, 0xee, 10)
            incs = sorted(incs + gs_incs + [0xee,])
    
        res = []
        for part in parts:
            i = 0
            while i < len(incs)-1:
                s, b = incs[i], incs[i+1]  # smaller, bigger
                if s <= part <= b:
                    s1 = abs(s - part)
                    b1 = abs(b - part)
                    if s1 < b1: closest = s
                    else: closest = b
                    res.append(closest)
                    break
                i += 1
        #print '***', res
        res = ''.join([ ('%02.x' % i) for i in res ])
        equiv = RGB2SHORT_DICT[ res ]
        #print '***', res, equiv
        return equiv, res
    
    RGB2SHORT_DICT, SHORT2RGB_DICT = _create_dicts()
    
    #---------------------------------------------------------------------
    
    if __name__ == '__main__':
        import doctest
        doctest.testmod()
        if len(sys.argv) == 1:
            print_all()
            raise SystemExit
        arg = sys.argv[1]
        if len(arg) < 4 and int(arg) < 256:
            rgb = short2rgb(arg)
            sys.stdout.write('xterm color \033[38;5;%sm%s\033[0m -> RGB exact \033[38;5;%sm%s\033[0m' % (arg, arg, arg, rgb))
            sys.stdout.write("\033[0m\n")
        else:
            short, rgb = rgb2short(arg)
            sys.stdout.write('RGB %s -> xterm color approx \033[38;5;%sm%s (%s)' % (arg, short, short, rgb))
            sys.stdout.write("\033[0m\n")
    

答案 4 :(得分:1)

tmux具有将24位RGB转换为256色的逻辑。它使用最接近的6x6x6或最接近的灰色之一。 https://github.com/tmux/tmux/blob/dae2868d1227b95fd076fb4a5efa6256c7245943/colour.c#L57

答案 5 :(得分:0)

您熟悉Floyd–Steinberg dithering吗?这用于将高阶颜色转换为低阶颜色,例如24位RGB到3位(8种颜色)RGB或将RGB图像限制为8位(256色)进行GIF转换。

此算法在链接的维基百科页面上进行了描述。

答案 6 :(得分:0)

如果要转换,请尝试此算法 24 bpp图像到8 bpp图像:

  $stateProvider
     .state('work-monitor', {
          url: '/work-monitor',
          templateUrl: 'templates/work-monitor.html',
     })
    ;

在此步骤之前,请阅读有关维基百科或其他来源的8bpp文件的更多信息。

祝你好运!