如何在C++中将16位十六进制颜色转换为RGB888值

3

我有一个uint16_t color需要转换为对应的RGB值。这个十六进制数前五位代表红色,接下来的六位代表绿色,最后五位代表蓝色。

到目前为止,我已经找到了一个接近解决方案但由于截断而不完全满足需求。

void hexToRGB(uint16_t hexValue)
{

    int r = ((hexValue >> 11) & 0x1F);  // Extract the 5 R bits
    int g = ((hexValue >> 5) & 0x3F);   // Extract the 6 G bits
    int b = ((hexValue) & 0x1F);        // Extract the 5 B bits

    r = ((r * 255) / 31) - 4;
    g = ((g * 255) / 63) - 2;
    b = ((b * 255) / 31) - 4;

    printf("r: %d, g: %d, b: %d\n",r, g, b);
}

int main()
{
    //50712=0xC618 
    hexToRGB(50712);    
    return 0;
}

上面的例子产生了r: 193, g: 192, b: 193,应该是r: 192, g: 192, b: 192。我一直在使用这个问题作为参考,但实际上我需要一个相反的解决方案,与他们所问的相反。

1
显然,用5位表示的值比用8位表示的值少,因此并不是所有值都能完美地往返转换。另外,你的转换公式很奇怪——0会被转换为负值。最简单的方法是将 rb 乘以8,将 g 乘以4——尽管这不会产生最纯净的白色(最白的颜色是 (248, 252, 248))。 - Igor Tandetnik
1
祝你好运。565很糟糕,不应该被创建。你永远无法使G组件与R和B匹配。看看两个除数31和63,以及其中一个是“有点多于”另一个的两倍? - gnasher729
2
转换方程肯定有问题。如果输入为0、0、0,则输出将为-4、-2、-4。 - Richard Critten
可能是重复的问题:https://dev59.com/LXE95IYBdhLWcg3wHqal - Rudy Velthuis
@gnasher729:由于人类对颜色的感知方式,绿色比其他颜色多了一位。如果你必须使用通常使用的亮度转换公式 0.21 R + 0.72 G + 0.07 B 将彩色转换为灰度,那么你会发现绿色也占主导地位。 - Rudy Velthuis
显示剩余6条评论
2个回答

7
以下是相关内容:

以下是相关内容:

unsigned r = (hexValue & 0xF800) >> 8;       // rrrrr... ........ -> rrrrr000
unsigned g = (hexValue & 0x07E0) >> 3;       // .....ggg ggg..... -> gggggg00
unsigned b = (hexValue & 0x1F) << 3;         // ............bbbbb -> bbbbb000

printf("r: %d, g: %d, b: %d\n", r, g, b);

这应该会得到0xC618 --> 192, 192, 192,但是0xFFFF --> 248, 252, 248,即不是纯白色。

如果您想让0xFFFF变成纯白色,则需要进行缩放,因此:

unsigned r = (hexValue & 0xF800) >> 11;
unsigned g = (hexValue & 0x07E0) >> 5;
unsigned b = hexValue & 0x001F;

r = (r * 255) / 31;
g = (g * 255) / 63;
b = (b * 255) / 31;

然后0xC618 --> 197、194、197,而不是预期的192、192、192,但0xFFFF是纯白色,0x0000是纯黑色。


感谢@Rudy Velthius发布此内容! - JayGarcia

5
没有一种“正确”的方法可以将RGB565比例转换为RGB888。每个颜色分量都需要从其5位或6位范围缩放到8位范围,而且有不同的方法来实现这个过程,通常会在图像中产生不同类型的视觉伪影。
当在n位范围内缩放颜色时,我们可能决定希望以下内容通常成立:
- 绝对黑色(例如5位空间中的00000)必须映射到8位空间中的绝对黑色; - 绝对白色(例如5位空间中的11111)必须映射到8位空间中的绝对白色;
实现这一点意味着我们基本上希望将值从n位空间中的(2n - 1)个阴影缩放到8位空间中的(28 - 1)个阴影。也就是说,我们希望以某种方式有效地执行以下操作:
r_8 = (255 * r / 31)
g_8 = (255 * g / 63)
b_8 = (255 * b / 31)

通常采用的不同方法包括:

  • 使用整数除法进行缩放
  • 使用浮点除法进行缩放然后四舍五入
  • 位移至8位空间并添加最高有效位

后一种方法实际上是以下内容

r_8 = (r << 3) | (r >> 2)
g_8 = (g << 2) | (g >> 4)
b_8 = (b << 3) | (b >> 2)

对于您的5位值11000,将会得到以下8位值:

  • 197
  • 197
  • 198 (11000000 | 110)

同样地,您的6位值110000将会得到以下8位值:

  • 194
  • 194
  • 195 (11000000 | 11)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接