简体   繁体   English

将 16 位颜色转换为 32 位

[英]Convert 16bit colour to 32bit

I've got an 16bit bitmap image with each colour represented as a single short (2 bytes), I need to display this in a 32bit bitmap context.我有一个 16 位位图图像,每种颜色表示为一个短(2 个字节),我需要在 32 位位图上下文中显示它。 How can I convert a 2 byte colour to a 4 byte colour in C++?如何在 C++ 中将 2 字节颜色转换为 4 字节颜色?

The input format contains each colour in a single short (2 bytes).输入格式在单个短(2 个字节)中包含每种颜色。

The output format is 32bit RGB.输出格式为 32 位 RGB。 This means each pixel has 3 bytes I believe?这意味着我相信每个像素有 3 个字节?

I need to convert the short value into RGB colours.我需要将短值转换为 RGB 颜色。

Excuse my lack of knowledge of colours, this is my first adventure into the world of graphics programming.请原谅我对颜色的了解不足,这是我第一次进入图形编程世界。

Normally a 16-bit pixel is 5 bits of red, 6 bits of green, and 5 bits of blue data.通常一个 16 位像素是 5 位红色、6 位绿色和 5 位蓝色数据。 The minimum-error solution (that is, for which the output color is guaranteed to be as close a match to the input colour) is:最小误差解决方案(即,保证输出颜色与输入颜色最接近)是:

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

To see why this solution works, let's look at at a red pixel.要了解此解决方案为何有效,让我们看一下红色像素。 Our 5-bit red is some fraction fivebit/31 .我们的 5 位红色是某个分数fivebit/31 We want to translate that into a new fraction eightbit/255 .我们想把它转换成一个新的分数eightbit/255 Some simple arithmetic:一些简单的算术:

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

Yields:产量:

     eightbit = fivebit * 8.226

Or closely (note the squiggly ≈):或者接近(注意波浪线 ≈):

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

That operation is a multiply by 8 and a divide by 4. Owch - both operations that might take forever on your hardware.该操作是乘以 8 和除以 4。Owch - 这两个操作可能会在您的硬件上永远运行。 Lucky thing they're both powers of two and can be converted to shift operations:幸运的是,它们都是 2 的幂,可以转换为移位操作:

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

The same steps work for green, which has six bits per pixel, but you get an accordingly different answer, of course!相同的步骤适用于每像素 6 位的绿色,但您当然会得到相应不同的答案! The quick way to remember the solution is that you're taking the top bits off of the "short" pixel and adding them on at the bottom to make the "long" pixel.记住解决方案的快速方法是您从“短”像素中取出最高位并将它们添加到底部以制作“长”像素。 This method works equally well for any data set you need to map up into a higher resolution space.此方法同样适用于您需要映射到更高分辨率空间的任何数据集。 A couple of quick examples:几个快速示例:

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

Common formats include BGR0, RGB0, 0RGB, 0BGR.常见的格式包括 BGR0、RGB0、0RGB、0BGR。 In the code below I have assumed 0RGB.在下面的代码中,我假设了 0RGB。 Changing this is easy, just modify the shift amounts in the last line.改变这很容易,只需修改最后一行中的移位量。

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);
*/
}

Multiply the three (four, when you have an alpha layer) values by 16 - that's it :)将三个(四个,当你有一个 alpha 层)值乘以 16 - 就是这样:)

You have a 16-bit color and want to make it a 32-bit color.您有 16 位颜色并希望将其设为 32 位颜色。 This gives you four times four bits, which you want to convert to four times eight bits.这为您提供了四乘以四位,您希望将其转换为四乘以八位。 You're adding four bits, but you should add them to the right side of the values.您正在添加四位,但您应该将它们添加到值的右侧。 To do this, shift them by four bits (multiply by 16).为此,将它们移位 4 位(乘以 16)。 Additionally you could compensate a bit for inaccuracy by adding 8 (you're adding 4 bits, which has the value of 0-15, and you can take the average of 8 to compensate)此外,您可以通过添加 8 来补偿不准确度(您添加了 4 位,其值为 0-15,您可以取 8 的平均值来补偿)

Update This only applies to colors that use 4 bits for each channel and have an alpha channel.更新这仅适用于每个通道使用 4 位并具有 Alpha 通道的颜色。

I'm here long after the fight, but I actually had the same problem with ARGB color instead , and none of the answers are truly right: Keep in mind that this answer gives a response for a slightly different situation where we want to do this conversion:我在这里打多久,但我实际上有与ARGB颜色相同的问题,而是和没有一个答案是真正正确的:请记住,这个答案让我们想这样做一个稍微不同的情况的响应转换:

AAAARRRRGGGGBBBB >>= AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB AAAARRRRGGGGBBBB >>= AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB

If you want to keep the same ratio of your color, you simply have to do a cross-multiplication: You want to convert a value x between 0 and 15 to a value between 0 and 255: therefore you want: y = 255 * x / 15 .如果您想保持相同的颜色比例,您只需进行交叉乘法:您想将 0 到 15 之间的值x转换为 0 到 255 之间的值:因此您想要: y = 255 * x / 15

However, 255 = 15 * 17, which itself, is 16 + 1: you now have y = 16 * x + x Which is actually the same as doing a for bits shift to the left and then adding the value again (or more visually, duplicating the value: 0b1101 becomes 0b11011101 ).然而,255 = 15 * 17,它本身就是 16 + 1:你现在有y = 16 * x + x这实际上与对位向左移动然后再次添加值(或更直观,复制值: 0b1101变为0b11011101 )。

Now that you have this, you can compute your whole number by doing:现在你有了这个,你可以通过执行以下操作来计算你的整数:

  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

Moreover, as the lower bits wont have much effect on the final color and if exactitude isnt necessary, you can gain some performances by simply multiplying each component by 16:此外,由于较低的位不会对最终颜色产生太大影响,而且如果不需要精确,您只需将每个分量乘以 16 即可获得一些性能:

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

(All the left shifts values are strange because we did not bother doing a right shift before) (所有的左移值都很奇怪,因为我们之前没有费心做右移)

There some questions about the model like is it HSV, RGB?有一些关于模型的问题,比如它是 HSV 还是 RGB? If you wanna ready, fire, aim I'd try this first.如果你想准备好,开火,瞄准,我会先试试这个。

#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);
}

This maps 0xRGBA -> 0xRRGGBBAA, or possibly 0xHSVA -> 0xHHSSVVAA, but it won't do 0xHSVA -> 0xRRGGBBAA.这会映射 0xRGBA -> 0xRRGGBBAA,或者可能是 0xHSVA -> 0xHHSSVVAA,但它不会映射 0xHSVA -> 0xRRGGBBAA。

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

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