c ++ определил 16-битный (высокий) цвет

Я работаю над проектом с сенсорным 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 в коде, потому что я просто хочу добавить несколько библиотек в библиотеку. Ссылка на онлайн-конвертер (который я не смог найти) тоже подойдет 🙂

Спасибо

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.

4

Другие решения

Похоже, вы используете RGB565, сначала 5 бит для красного, затем 6 бит для зеленого, затем 5 бит для синего.

Вы должны замаскировать с 0xF800 и сдвинуть вправо на 11 бит, чтобы получить красный компонент (или сдвинуть 8 бит, чтобы получить значение от 0 до 255).
Маска с 0x07E0 и сдвиг вправо на 5 бит, чтобы получить зеленый компонент (или 3, чтобы получить значение 0-255).
Маска с 0x001F, чтобы получить синий компонент (и сдвиг влево на 3 бита, чтобы получить 0-255).

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-битные компоненты, тогда потребуется дополнительное масштабирование.

4

Ваши цвета в формате 565. Было бы более очевидно, если бы вы записали их в двоичном виде.

  • Синий (0,0255) равен 0x001f, что составляет 00000 000000 11111
  • Зеленый, (0, 255, 0) равен 0x07e0, что составляет 00000 111111 00000
  • Красный, (255, 0, 0) равен 0xf800, что составляет 11111 000000 00000

Чтобы преобразовать 24-битный цвет в 16-битный в этом формате, просто замаскируйте верхние биты, необходимые для каждого компонента, сдвиньте в позицию и OR все вместе.

Преобразуйте обратно в 24-битный цвет из 16-битного, замаскируйте каждый компонент, сдвиньте в позицию, а затем дублируйте старшие биты в младшие биты.

В ваших примерах кажется, что некоторые цвета были масштабированы и округлены, а не смещены.

Я настоятельно рекомендую использовать метод битового сдвига, а не масштабировать с коэффициентом, подобным 31/255, потому что битовый сдвиг не только будет быстрее, но и даст лучшие результаты.

3

Показанные вами 3-значные номера применимы к 24-битному цвету. 128 в шестнадцатеричном формате — это 0x7f, но в ваших определениях цвета он представлен как 0x0f. Аналогично, 255 — это 0xff, но в ваших определениях цвета он представлен как 0x1f. Это говорит о том, что вам нужно взять номера из 3-х частей и сдвинуть их на 3 бита (теряя 3 бита цветовых данных для каждого цвета). Затем объедините их в одно 16-битное число:

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

…пересмотрено ранее, потому что зеленый использует 6 бит, а не 5.

1

Вы должны знать, сколько битов на цветовой канал. Так что да, для цвета есть 16 битов, но каждый компонент RGB является некоторым подмножеством этих битов. В вашем случае красный — 5 бит, зеленый — 6, а синий — 5. Формат в двоичном виде будет выглядеть так:

RRRRRGGG GGGBBBBB

Существуют другие 16-битные форматы цвета, такие как красный, зеленый и синий, каждый из которых имеет 5 бит, а затем использует оставшийся бит для значения альфа.

Диапазон значений для красного и синего каналов будет от 0 в 2^5-1 = 31в то время как диапазон для зеленого будет 0 в 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 11101111 который 0x03EF,

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)

Возможно, вам потребуется замаскировать любые ненужные биты после смен, поскольку я не уверен, как это работает, но я думаю, что приведенный выше код должен работать.

1

Основываясь на ответе раскрутки, в частности, для библиотеки Adafruit GFX с использованием Arduino 2.8 «TFT Touchscreen (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;
}

Теперь вы можете использовать его встроенным образом, как показано на рисунке, с помощью функции, которая создает квадрат 20×20 в x0, 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 можно найти Вот

1