c ++定义的16位(高)颜色

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13720937/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:40:19  来源:igfitidea点击:

c++ defined 16bit (high) color

c++colorscolor-picker16-bit

提问by Bart Teunissen

I am working on a project with a TFT touch screen, with this screen there is an included library. But after some reading, i still dont get something. In the library there are some defines regarding colors:

我正在处理一个带有 TFT 触摸屏的项目,这个屏幕有一个包含的库。但经过一些阅读,我仍然没有得到一些东西。在库中,有一些关于颜色的定义:

/* some RGB color definitions                                                 */
#define Black           0x0000      /*   0,   0,   0 */
#define Navy            0x000F      /*   0,   0, 128 */
#define DarkGreen       0x03E0      /*   0, 128,   0 */
#define DarkCyan        0x03EF      /*   0, 128, 128 */
#define Maroon          0x7800      /* 128,   0,   0 */
#define Purple          0x780F      /* 128,   0, 128 */
#define Olive           0x7BE0      /* 128, 128,   0 */
#define LightGrey       0xC618      /* 192, 192, 192 */
#define DarkGrey        0x7BEF      /* 128, 128, 128 */
#define Blue            0x001F      /*   0,   0, 255 */
#define Green           0x07E0      /*   0, 255,   0 */
#define Cyan            0x07FF      /*   0, 255, 255 */
#define Red             0xF800      /* 255,   0,   0 */
#define Magenta         0xF81F      /* 255,   0, 255 */
#define Yellow          0xFFE0      /* 255, 255,   0 */
#define White           0xFFFF      /* 255, 255, 255 */
#define Orange          0xFD20      /* 255, 165,   0 */
#define GreenYellow     0xAFE5      /* 173, 255,  47 */
#define Pink                        0xF81F

Those are 16 bit colors. But how do they go from: 0,128,128(dark cyan) to 0x03EF. I mean, how do you convert a 16bit color to a uint16? this doesn't need to have a anwser in code, because i just want to add some collors in the library. A link to a online converter (wich i could not find) would be okay as well :)

这些是 16 位颜色。但是它们如何从:0,128,128(深青色)到 0x03EF。我的意思是,如何将 16 位颜色转换为 uint16?这不需要在代码中有 anwser,因为我只想在库中添加一些颜色。指向在线转换器的链接(我找不到)也可以:)

Thanks

谢谢

采纳答案by Aki Suihkonen

From these one can easily find out the formula:

从这些中可以很容易地找出公式:

#define Red             0xF800      /* 255,   0,   0 */  
#define Magenta         0xF81F      /* 255,   0, 255 */
#define Yellow          0xFFE0      /* 255, 255,   0 */

F800 has 5 MSB bits set and FFE0 has 5 LSB not set. 0xF81F has obviously both 5 LSB's and 5 MSB's set, which proves the format to be RGB565.

F800 设置了 5 个 MSB 位,FFE0 设置了 5 个 LSB。0xF81F 显然有 5 个 LSB 和 5 个 MSB 的集合,这证明格式是 RGB565。

The formula to convert a value 173 to Red is not as straightforward as it may look -- you can't simply drop the 3 least significant bits, but have to linearly interpolate to make 255 to correspond to 31 (or green 255 to correspond to 63).

将值 173 转换为红色的公式并不像看起来那么简单——您不能简单地删除 3 个最低有效位,而是必须线性插值以使 255 对应于 31(或绿色 255 对应于63)。

NewValue = (31 * old_value) / 255;

(And this is still just a truncating division -- proper rounding could be needed)

(这仍然只是一个截断除法——可能需要适当的四舍五入)

With proper rounding and scaling:

使用适当的舍入和缩放:

Uint16_value = (((31*(red+4))/255)<<11) | 
               (((63*(green+2))/255)<<5) | 
               ((31*(blue+4))/255);

EDITAdded parenthesis to as helpfully suggested by JasonD.

编辑根据 JasonD 的建议,添加了括号。

回答by unwind

You need to know the exact format of the display, just "16-bit" is not enough.

您需要知道显示器的确切格式,仅“16 位”是不够的。

There's RGB555, in which each of the three components get 5 bits. This drops the total color space to just 32,768 colors, wasting one bit but it's very simple to manage since the there's the same number of shades for each component.

有 RGB555,其中三个组件中的每一个都有 5 位。这将总色彩空间降低到只有 32,768 种颜色,浪费了一点,但管理起来非常简单,因为每个组件都有相同数量的色调。

There's also RGB565, in which the green component is given 6 bits (since the human eye is more sensitive to green). This might be the format you're having, since the "dark green" example is 0x03e0which in binary is 0b0000 0011 1110 0000. Since there's 6 bits set to 1 there, I guess that's the total allocation for the green component and showing it's maximum value.

还有RGB565,其中绿色成分被赋予6位(因为人眼对绿色更敏感)。这可能是您使用的格式,因为“深绿色”示例是0x03e0二进制文件中的0b0000 0011 1110 0000. 由于那里有 6 位设置为 1,我想这是绿色组件的总分配并显示它的最大值。

It's like this, then (with spaces separating every four bits and re-using the imaginary 0bprefix):

就是这样,然后(用空格分隔每四位并重新使用假想0b前缀):

0bRRRR RGGG GGGB BBBB

Of course, the bit ordering can differ too, in the word.

当然,位顺序也可以不同,就字而言。

The task of converting a triplet of numbers into a bit-packed word is quite easily done in typically programming languages that have bit manipulation operators.

将三元组数字转换为位压缩字的任务在具有位操作运算符的典型编程语言中很容易完成。

In C, it's often done in a macro, but we can just as well have a function:

在 C 中,它通常在宏中完成,但我们也可以拥有一个函数:

#include <stdint.h>

uint16_t rgb565_from_triplet(uint8_t red, uint8_t green, uint8_t blue)
{
  red   >>= 3;
  green >>= 2;
  blue  >>= 3;
  return (red << 11) | (green << 5) | blue;
}

note that the above assumes full 8-bit precision for the components, so maximum intensity for a component is 255, not 128 as in your example. If the color space really is using 7-bit components then some additional scaling would be necessary.

请注意,以上假设组件具有完整的 8 位精度,因此组件的最大强度为 255,而不是您的示例中的 128。如果色彩空间确实使用 7 位组件,则需要进行一些额外的缩放。

回答by Karl E

It looks like you're using RGB565, first 5 bits for Red, then 6 bits for Green, then 5 bits for Blue.

看起来您使用的是 RGB565,前 5 位用于红色,然后是 6 位用于绿色,然后是 5 位用于蓝色。

You should mask with 0xF800 and shift right 11 bits to get the red component (or shift 8 bits to get a value from 0-255). Mask with 0x07E0 and shift right 5 bits to get green component (or 3 to get a 0-255 value). Mask with 0x001F to get the blue component (and shift left 3 bits to get 0-255).

您应该使用 0xF800 进行屏蔽并右移 11 位以获得红色分量(或移动 8 位以获得 0-255 的值)。用 0x07E0 屏蔽并右移 5 位以获得绿色分量(或 3 以获得 0-255 值)。用 0x001F 屏蔽以获得蓝色分量(并左移 3 位以获得 0-255)。

回答by JasonD

Your colours are in 565 format. It would be more obvious if you wrote them out in binary.

您的颜色采用 565 格式。如果你把它们写成二进制会更明显。

  • Blue, (0,0,255) is 0x001f, which is 00000 000000 11111
  • Green, (0, 255, 0) is 0x07e0, which is 00000 111111 00000
  • Red, (255, 0, 0) is 0xf800, which is 11111 000000 00000
  • 蓝色,(0,0,255) 是 0x001f,也就是 00000 000000 11111
  • 绿色,(0, 255, 0) 为 0x07e0,即 00000 111111 00000
  • 红色,(255, 0, 0) 是 0xf800,也就是 11111 000000 00000

To convert a 24 bit colour to 16 bit in this format, simply mask off the upper bits needed from each component, shift into position, and ORtogether.

要将这种格式的 24 位颜色转换为 16 位颜色,只需屏蔽每个组件所需的高位,移位到位置,然后OR一起。

The convert back into 24 bit colour from 16 bit, mask each component, shift into position, and then duplicate the upper bits into the lower bits.

从 16 位转换回 24 位颜色,屏蔽每个组件,移位到位,然后将高位复制到低位。

In your examples it seems that some colours have been scaled and rounded rather than shifted.

在您的示例中,似乎某些颜色已被缩放和四舍五入而不是移位。

I strongly recommend using the bit-shift method rather than scaling by a factor like 31/255, because the bit-shifting is not only likely to be faster, but should give better results.

我强烈建议使用位移方法而不是像 31/255 这样的因子进行缩放,因为位移不仅可能更快,而且应该会给出更好的结果。

回答by phonetagger

The 3-part numbers you're showing are applicable to 24-bit color. 128 in hex is 0x7f, but in your color definitions, it's being represented as 0x0f. Likewise, 255 is 0xff, but in your color definitions, it's being represented as 0x1f. This suggests that you need to take the 3-part numbers and shift them down by 3 bits (losing 3 bits of color data for each color). Then combine them into a single 16-bit number:

您显示的 3 部分数字适用于 24 位颜色。十六进制的 128 是 0x7f,但在您的颜色定义中,它被表示为 0x0f。同样,255 是 0xff,但在您的颜色定义中,它表示为 0x1f。这表明您需要取 3 部分数字并将它们向下移动 3 位(每种颜色丢失 3 位颜色数据)。然后将它们组合成一个 16 位数字:

uint16 color = ((red>>3)<<11) | ((green>>2)<<5) | (blue>>3);

...revised from earlier because green uses 6 bits, not 5.

...从之前修订,因为绿色使用 6 位,而不是 5。

回答by Joseph Mansfield

You need to know how many bits there are per colour channel. So yes, there are 16 bits for a colour, but the RGB components are each some subset of those bits. In your case, red is 5 bits, green is 6, and blue is 5. The format in binary would look like so:

您需要知道每个颜色通道有多少位。所以是的,一种颜色有 16 位,但 RGB 分量都是这些位的某个子集。在您的情况下,红色是 5 位,绿色是 6 位,蓝色是 5 位。二进制格式如下所示:

RRRRRGGG GGGBBBBB

There are other 16 bit colour formats, such as red, green, and blue each being 5 bits and then use the remaining bit for an alpha value.

还有其他 16 位颜色格式,例如红色、绿色和蓝色,每一种都是 5 位,然后使用剩余的位作为 alpha 值。

The range of values for both the red and blue channels will be from 0to 2^5-1 = 31, while the range for green will be 0to 2^6-1 = 63. So to convert from colours in the form of (0->255),(0->255),(0->255)you will need to map values from one to the other. For example, a red value of 128in the range 0->255will be mapped to (128/255) * 31 = 15.6in the red channel with range 0-31. If we round down, we get 15which is represented as 01111in five bits. Similarly, for the green channel (with six bits) you will get 011111. SO the colour (128,128,128)will map to 01111011 11101111which is 0x7BEFin hexadecimal.

红色和蓝色通道的值范围都是从02^5-1 = 31,而绿色的范围是02^6-1 = 63。因此,要从 形式的颜色转换,(0->255),(0->255),(0->255)您需要将值从一种映射到另一种。例如,128范围内的红色值0->255将映射到(128/255) * 31 = 15.6具有范围的红色通道中0-31。如果我们向下取整,我们会得到用五位15表示的01111。同样,对于绿色通道(六位),您将获得011111. 所以颜色(128,128,128)将映射到01111011 11101111它是0x7BEF十六进制的。

You can apply this to the other values too: 0,128,128becomes 00000011 11101111which is 0x03EF.

您也可以将其应用于其他值:0,128,128成为00000011 11101111which is 0x03EF

回答by B_o_b

Those colours shown in your code are RGB565. As shown by

代码中显示的那些颜色是 RGB565。如图所示

#define Blue            0x001F      /*   0,   0, 255 */ 
#define Green           0x07E0      /*   0, 255,   0 */ 
#define Red             0xF800      /* 255,   0,   0 */

If you simply want to add some new colours to this #definedlist, the simplest way to convert from 16bit UINT per channel is just to shift your values down to loose the the low order bits and then shift and (or) them into position in the 16bitRGB value. This could well produce banding artefacts though, and there may well be a better conversion method.

如果您只是想向此#defined列表添加一些新颜色,从每个通道的 16 位 UINT 转换的最简单方法就是将您的值向下移动以松开低位,然后将它们移动和(或)到 16bitRGB 中的位置价值。不过,这很可能会产生条带伪影,并且很可能有更好的转换方法。

i.e.

IE

UINT16 blue = 0xFF;
UINT16 green = 0xFF;
UINT16 red = 0xFF;


blue  >>= 11; // top 5 bits
green >>= 10; // top 6 bits
red   >>= 11; // top 5 bits

UINT16 RGBvalue = blue | (green <<5) | (red << 11)

You may need to mask of any unwanted stray bits after the shifts, as I am unsure how this works, but I think the code above should work.

您可能需要在移位后屏蔽任何不需要的杂散位,因为我不确定这是如何工作的,但我认为上面的代码应该可以工作。

回答by Jeff Weinberg

Building on unwind's answer, specifically for the Adafruit GFX library using the Arduino 2.8" TFT Touchscreen(v2), you can add this function to your Arduino sketch and use it inline to calculate colors from rgb:

基于 unwind 的答案,特别是针对使用 Arduino 2.8" TFT 触摸屏 (v2) 的 Adafruit GFX 库,您可以将此功能添加到您的 Arduino 草图中,并使用它内联从 rgb 计算颜色:

uint16_t getColor(uint8_t red, uint8_t green, uint8_t blue)
{
  red   >>= 3;
  green >>= 2;
  blue  >>= 3;
  return (red << 11) | (green << 5) | blue;
}

Now you can use it inline as so, illustrated with a function that creates a 20x20 square at x0,y0:

现在你可以像这样内联使用它,用一个在 x0,y0 处创建一个 20x20 正方形的函数来说明:

void setup() {
  tft.begin();
  makeSquare(getColor(20,157,217));
}

unsigned long makeSquare(uint16_t color1) {
  tft.fillRect(0, 0, 20, 20, color1);
}

Docs for the Adafruit GFX library can be found here

可以在此处找到 Adafruit GFX 库的文档