8

我正在开发一个带有 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?这不需要在代码中有答案,因为我只想在库中添加一些颜色。一个在线转换器的链接(我找不到)也可以:)

谢谢

4

8 回答 8

6

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

#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 的有益建议添加了括号。

于 2012-12-05T10:35:46.363 回答
5

您需要知道显示的确切格式,仅“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 位组件,则需要进行一些额外的缩放。

于 2012-12-05T10:27:05.410 回答
4

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

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

于 2012-12-05T10:35:40.840 回答
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 这样的因子进行缩放,因为位移不仅可能更快,而且应该会产生更好的结果。

于 2012-12-05T10:36:16.550 回答
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 位。

于 2012-12-05T10:39:46.907 回答
1

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

RRRRRGGG GGGBBBBB

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

红色和蓝色通道的值范围是 from02^5-1 = 31,而绿色的范围是0to 2^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 11101111which is 0x03EF

于 2012-12-05T10:40:14.617 回答
1

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

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

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

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)

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

于 2012-12-05T10:51:19.627 回答
1

基于 unwind 的回答,特别是使用 Arduino 2.8" TFT Touchscreen(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;
}

现在您可以像这样内联使用它,用一个在 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);
}

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

于 2014-05-18T17:35:12.633 回答