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

时间:2012-12-05 10:21:24

标签: c++ colors color-picker 16-bit

我正在开发一个带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

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

谢谢

8 个答案:

答案 0 :(得分:5)

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

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

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

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

NewValue = (31 * old_value) / 255;

(这仍然只是一个截断分区 - 可能需要进行适当的舍入)

适当的舍入和缩放:

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

编辑在JasonD的帮助下添加了括号。

答案 1 :(得分:4)

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

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

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

就像这样,然后(用空格分隔每四位并重新使用虚构的0b前缀):

0bRRRR RGGG GGGB BBBB

当然,在单词中,位顺序也可能不同。

在具有位操作算子的典型编程语言中,将三重数字转换为位打包字的任务非常容易。

在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;
}

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

答案 2 :(得分:4)

看起来你正在使用RGB565,前5位用于红色,然后6位用于绿色,然后5位用于蓝色。

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

答案 3 :(得分:3)

您的颜色为565格式。如果你用二进制文件写出它们会更加明显。

  • 蓝色,(0,0,255)为0x001f,即00000 000000 11111
  • 绿色,(0,255,0)为0x07e0,即00000 111111 00000
  • 红色,(255,0,0)为0xf800,即11111 000000 00000

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

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

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

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

答案 4 :(得分:1)

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

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

...从早期修改,因为绿色使用6位,而不是5位。

答案 5 :(得分:1)

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

RRRRRGGG GGGBBBBB

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

红色和蓝色通道的值范围将从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为十六进制。

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

答案 6 :(得分:1)

代码中显示的颜色为RGB565。如

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

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

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)

你可能需要在转换后屏蔽任何不需要的杂散位,因为我不确定它是如何工作的,但我认为上面的代码应该有效。

答案 7 :(得分:1)

基于放松的答案,特别针对使用Arduino 2.8&#34;的Adafruit GFX库。 TFT触摸屏(v2),您可以将此功能添加到您的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;
}

现在您可以将其内联使用,使用在x0处创建20x20平方的函数进行说明,y0:

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

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

可以找到Adafruit GFX库的文档here