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


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

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

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

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

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

这样我总能有比赛。

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


10852
2017-10-09 20:08


起源

你用的是什么语言?也许某些图书馆已经成功了。 - Francis P
8位颜色可以通过几种不同的方式完成。它可能是颜色表的索引,或RRRGGGBB值等。您希望使用哪种8位颜色? - cHao
8位不足以表示任意颜色。 - Mark Ransom
我正在考虑在GIF图像中使用的方法。 GIF图像只有8位颜色,如果您使用网页安全颜色,您可以获得非常好的图像。 - bodacydo
@MarkRansom看看GIF 8位网页安全调色板的外观: htmlgoodies.com/imagesvr_ce/7234/Figure_06.gif 我会说你得到了一个很好的近似值。 - bodacydo


答案:


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

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

8
2017-10-09 21:48





您需要做的是将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转换器。


6
2017-10-09 21:43



我自己用2位饱和度和2位亮度。 - Mark Ransom


一种可能性是简单地将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指出的缺点。


2
2018-05-28 20:00



只有8位的颜色范围,忽略位边界并使用不是2的幂的范围更有意义。你的答案有8个可能的红色,8个可能的绿色,但只有4个可能的蓝色;更典型的是6,6,6(如我的回答)或6,7,6。您的缩放也有点偏,因为只有255的输入才能提供最大输出,而这些值将不足。 - Mark Ransom
确实如此。我真的只是想详细阐述cHao的评论。我编辑了我的答案来解决缩放问题。 - Michael Calvin
JSBin: jsbin.com/voqacamema/3 - Harsh Vakharia


你熟悉吗? 弗洛伊德 - 斯坦伯格犹豫不决?这用于将高阶颜色转换为低阶颜色,例如24位RGB至3位(8色)RGB或将RGB图像限制为8位(256色)以进行GIF转换。

该算法在链接的维基百科页面上描述。


0
2017-10-09 21:42



想法是转换单一颜色。抖动在这个应用程序中没有意义。 - Mark Ransom


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

for y = 0 to ImageHeight - 1
   for x = 0 to ImageWidth - 1
      GetPixel(x,y,red,grn,blu)
      {read RGB data from 24bpp file}
      d0 = red^2 + grn^2 + blu^2
      ColorIndex = 0
      for cl = 0 to 255
         GetPaletteData(p_red,p_gre,p_blu)
         {read RGB data from 8bpp palette}
         d = (red - p_red)^2 + (grn - p_grn)^2 + (blu - p_blu)^2
         if d0 >= d then
            ColorIndex = cl
            d0 = d
         end if
      next cl
        {use ColorIndex to create your 8bpp file}
     next x
   next y

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

祝你好运!


0
2017-12-14 20:29