Влияние регулировки компонента Y в YUV? - PullRequest
1 голос
/ 04 марта 2020

Я занимался реверс-инжинирингом программы и недавно наткнулся на функцию, предназначенную для создания своего рода полупрозрачного цвета, который будет использоваться для выделения текста. Это достигается путем преобразования RGB в YUV, изменения компонента Y (luma?), А затем преобразования обратно в RGB.

uint32_t CalcSelectionColor(uint32_t bgr)
{
  double r,g,b;
  double y,u,v;

  r = (bgr >>  0) & 0xFF;
  g = (bgr >>  8) & 0xFF;
  b = (bgr >> 16) & 0xFF;

  /* RGB to YUV */
  y = 0.299*r + 0.587*g + 0.114*b;
  u = (b-y) * 0.565 * 0.5;
  v = (r-y) * 0.713 * 0.5;

  /* lower brightness? */
  y = 255.0 - y;

  /* YUV to RGB */
  r = y + 1.403*v;
  g = y - 0.344*u - 0.714*v;
  b = y + 1.77*u;

  return ((uint8_t)(b) << 16) | ((uint8_t)(g) << 8) | ((uint8_t)(r));
}

Как человек с очень ограниченным знанием компьютерной графики, я бы хотел немного подробнее о том, что он делает между преобразованиями, и о фактически намеченном эффекте в более широком смысле. Это обычный подход регулировки яркости цвета или что-то? Если я передам 0x00FF00, то получу результат 0x1E9D1E

Ответы [ 2 ]

2 голосов
/ 04 марта 2020

Это не очень часто, но это очень хороший подход. Обычно используемые модели, такие как HSL / HSV, неправильно отображают интенсивность и имеют некоторые странные кусочно-линейные вещи с продолжающимся оттенком / цветом. YUV - действительно хорошее цветовое пространство, представляющее интенсивность вдоль одной оси и насыщенность цвета (оттенок / цвет) в перпендикулярной плоскости.

Обычно изменение Y без настройки (по крайней мере, фиксации) U и V несколько сомнительно, потому что крайние значения (Y = 0 черный, Y = полный белый) U и V имеют ограниченный диапазон (вообще никакого диапазона в конечных точках). В противном случае их применение выведет вас за пределы RGB-куба и приведет к фиктивным обрезанным результатам, когда вы вернетесь к RGB. Но тут уловка очень умная. Код инвертирует Y, сохраняя цветность фиксированной, поэтому пределы входного диапазона для U и V вблизи черного автоматически обеспечат их приблизительную корректность на выходе, и наоборот.

Как Алекс отметил, что код здесь также вдвое уменьшает значения цветности, уменьшая насыщенность цвета. Вероятно, это было сделано для того, чтобы избежать упомянутой выше проблемы с отсечкой, но это не нужно. Но, возможно, это тоже часть предполагаемого визуального эффекта.

Итак, TL; DR: эффект инвертирует интенсивность / яркость и наполовину насыщенность.

2 голосов
/ 04 марта 2020

Формулы, используемые в этом коде, похожи на преобразование Жюльена из RGB в YUV и обратно:

Transformation from RGB to YUV:

   Y = 0.299R + 0.587G + 0.114B
   U'= (B-Y)*0.565
   V'= (R-Y)*0.713

Transformation from YUV to RGB:

   R = Y + 1.403V'
   G = Y - 0.344U' - 0.714V'
   B = Y + 1.770U'

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

y = 255.0 - y

, который просто инвертирует яркость. Итак, что здесь происходит?

Если вы используете обычное преобразование Julien RGB-> YUV, вы получите представление для вашего цвета в виде комбинации яркости Y и двух компонентов цветового тона U и V, которые определяют цвет как показано на этом рисунке:

UV color plane

Однако в вашем коде вы также умножаете компоненты U и V на 0,5. Это означает, что на этой плоскости УФ вы перемещаетесь от любого данного цвета в два раза ближе к точке происхождения (0, 0). Например, если исходный цвет был A с координатами UV (-0,4, 0,3), то вы получите новый цвет B с координатами UV (-0,2, 0,15). Аналогично, цвет C (0,2, -0,3) становится цветом D (0,1, -0,15):

UV color change

После этого вы меняете яркость цвета, делая темные цвета яркими, а яркие цвета темными. Это эффект вашего кода.

...