繁体   English   中英

将 16 位颜色转换为 32 位

[英]Convert 16bit colour to 32bit

我有一个 16 位位图图像,每种颜色表示为一个短(2 个字节),我需要在 32 位位图上下文中显示它。 如何在 C++ 中将 2 字节颜色转换为 4 字节颜色?

输入格式在单个短(2 个字节)中包含每种颜色。

输出格式为 32 位 RGB。 这意味着我相信每个像素有 3 个字节?

我需要将短值转换为 RGB 颜色。

请原谅我对颜色的了解不足,这是我第一次进入图形编程世界。

通常一个 16 位像素是 5 位红色、6 位绿色和 5 位蓝色数据。 最小误差解决方案(即,保证输出颜色与输入颜色最接近)是:

red8bit   = (red5bit << 3) | (red5bit >> 2);
green8bit = (green6bit << 2) | (green6bit >> 4);
blue8bit  = (blue5bit << 3) | (blue5bit >> 2);

要了解此解决方案为何有效,让我们看一下红色像素。 我们的 5 位红色是某个分数fivebit/31 我们想把它转换成一个新的分数eightbit/255 一些简单的算术:

     fivebit   eightbit
     ------- = --------
        31        255

产量:

     eightbit = fivebit * 8.226

或者接近(注意波浪线 ≈):

     eightbit ≈ (fivebit * 8) + (fivebit * 0.25)

该操作是乘以 8 和除以 4。Owch - 这两个操作可能会在您的硬件上永远运行。 幸运的是,它们都是 2 的幂,可以转换为移位操作:

     eightbit = (fivebit << 3) | (fivebit >> 2);

相同的步骤适用于每像素 6 位的绿色,但您当然会得到相应不同的答案! 记住解决方案的快速方法是您从“短”像素中取出最高位并将它们添加到底部以制作“长”像素。 此方法同样适用于您需要映射到更高分辨率空间的任何数据集。 几个快速示例:

    five bit space         eight bit space        error
    00000                  00000000                 0%
    11111                  11111111                 0%
    10101                  10101010                0.02%
    00111                  00111001               -1.01%

常见的格式包括 BGR0、RGB0、0RGB、0BGR。 在下面的代码中,我假设了 0RGB。 改变这很容易,只需修改最后一行中的移位量。

unsigned long rgb16_to_rgb32(unsigned short a)
{
/* 1. Extract the red, green and blue values */

/* from rrrr rggg gggb bbbb */
unsigned long r = (a & 0xF800) >11;
unsigned long g = (a & 0x07E0) >5;
unsigned long b = (a & 0x001F);

/* 2. Convert them to 0-255 range:
There is more than one way. You can just shift them left:
to 00000000 rrrrr000 gggggg00 bbbbb000
r <<= 3;
g <<= 2;
b <<= 3;
But that means your image will be slightly dark and
off-colour as white 0xFFFF will convert to F8,FC,F8
So instead you can scale by multiply and divide: */

r = r * 255 / 31;
g = g * 255 / 63;
b = b * 255 / 31;
/* This ensures 31/31 converts to 255/255 */

/* 3. Construct your 32-bit format (this is 0RGB): */
return (r << 16) | (g << 8) | b;

/* Or for BGR0:
return (r << 8) | (g << 16) | (b << 24);
*/
}

将三个(四个,当你有一个 alpha 层)值乘以 16 - 就是这样:)

您有 16 位颜色并希望将其设为 32 位颜色。 这为您提供了四乘以四位,您希望将其转换为四乘以八位。 您正在添加四位,但您应该将它们添加到值的右侧。 为此,将它们移位 4 位(乘以 16)。 此外,您可以通过添加 8 来补偿不准确度(您添加了 4 位,其值为 0-15,您可以取 8 的平均值来补偿)

更新这仅适用于每个通道使用 4 位并具有 Alpha 通道的颜色。

我在这里打多久,但我实际上有与ARGB颜色相同的问题,而是和没有一个答案是真正正确的:请记住,这个答案让我们想这样做一个稍微不同的情况的响应转换:

AAAARRRRGGGGBBBB >>= AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB

如果您想保持相同的颜色比例,您只需进行交叉乘法:您想将 0 到 15 之间的值x转换为 0 到 255 之间的值:因此您想要: y = 255 * x / 15

然而,255 = 15 * 17,它本身就是 16 + 1:你现在有y = 16 * x + x这实际上与对位向左移动然后再次添加值(或更直观,复制值: 0b1101变为0b11011101 )。

现在你有了这个,你可以通过执行以下操作来计算你的整数:

  a = v & 0b1111000000000000
  r = v & 0b111100000000
  g = v & 0b11110000
  b = v & 0b1111
  return b | b << 4 | g << 4 | g << 8 | r << 8 | r << 12 | a << 12 | a << 16

此外,由于较低的位不会对最终颜色产生太大影响,而且如果不需要精确,您只需将每个分量乘以 16 即可获得一些性能:

  return b << 4 | g << 8 | r << 12 | a << 16

(所有的左移值都很奇怪,因为我们之前没有费心做右移)

有一些关于模型的问题,比如它是 HSV 还是 RGB? 如果你想准备好,开火,瞄准,我会先试试这个。

#include <stdint.h>

uint32_t convert(uint16_t _pixel) 
{
    uint32_t pixel;
    pixel = (uint32_t)_pixel;
    return ((pixel & 0xF000) << 16)
         | ((pixel & 0x0F00) << 12)
         | ((pixel & 0x00F0) << 8)
         | ((pixel & 0x000F) << 4);
}

这会映射 0xRGBA -> 0xRRGGBBAA,或者可能是 0xHSVA -> 0xHHSSVVAA,但它不会映射 0xHSVA -> 0xRRGGBBAA。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM