Обработка изображений 5. Цветовые модели

от
Работа с графикой   image processing, обработка изображений, javascript, js, cmyk, hsl, hsb, цветовые модели

logo.png
Работать с моделью RGB не всегда удобно. Например, принтер не подчиняется RGB-модели, потому что бумагу ему подают белую и на светлые тона он тратит меньше краски. Поэтому существует множество моделей, призванных решать разного рода задачи. Об основных цветовых моделях и пойдёт речь. А чтобы не было скучно, покрутим немного ползунки.

Содержание:
  1. Введение
  2. Изображения. Простая трансформация
  3. Негатив, извлечение и инверсия каналов
  4. Обесцвечивание
  5. Цветовые модели
  6. Яркость, насыщенность, контрастность, гамма-коррекция
  7. Гистограмма
  8. Масштабирование изображения
  9. Размытие
  10. Свёртка

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

Фильтр RGB-коррекции реализуется очень просто. Есть три ползунка с диапазоном от -255 до 255 включительно, по одному на каждую цветовую компоненту.
  1. <input id="rangeR" type="range" min="-255" max="255" value="0" />
  2. <input id="rangeG" type="range" min="-255" max="255" value="0" />
  3. <input id="rangeB" type="range" min="-255" max="255" value="0" />
Дальше просто проходим по массиву пикселей, разбиваем пиксель на три компоненты и прибавляем соответствующее значение. Важно не забыть ограничить полученный результат диапазоном 0..255.
  1. let deltaR = parseInt($("#rangeR").val());
  2. let deltaG = parseInt($("#rangeG").val());
  3. let deltaB = parseInt($("#rangeB").val());
  4. for (let i = 0; i < dst.length; i++) {
  5.   let r = src[i] & 0xFF;
  6.   let g = (src[i] >> 8) & 0xFF;
  7.   let b = (src[i] >> 16) & 0xFF;
  8.  
  9.   r += deltaR;
  10.   g += deltaG;
  11.   b += deltaB;
  12.   if (r > 255) r = 255;
  13.   else if (r < 0) r = 0;
  14.   if (g > 255) g = 255;
  15.   else if (g < 0) g = 0;
  16.   if (b > 255) b = 255;
  17.   else if (b < 0) b = 0;
  18.  
  19.   dst[i] = (src[i] & 0xFF000000) | (b << 16) | (g << 8) | r;
  20. }

See the Pen Image processing 5.1. RGB correction by aNNiMON (@aNNiMON) on CodePen.


Оригинал слева и R=41 G=-7 B=-18:
index.jpg rgb_41_-7_-18.jpg


ЯркостьЕсли же регулировать одновременно три значения, то получится фильтр Яркость.

See the Pen Image processing 5.2. Brightness by aNNiMON (@aNNiMON) on CodePen.


Оригинал слева и яркость=-45:
index.jpg br_-45.jpg

Цветовая модель CMYKCMYK (cyan, magenta, yellow, black) применяется в типографии. Принтеру подают белую бумагу и он, смешивая голубой, пурпурный и жёлтый, получает необходимый цвет. Для экономии цветной краски используется четвёртый компонент K – интенсивность чёрного.

Значения теперь будем указывать в процентах.
  1. let deltaC = parseInt($("#rangeC").val()) / 100.0;
  2. let deltaM = parseInt($("#rangeM").val()) / 100.0;
  3. let deltaY = parseInt($("#rangeY").val()) / 100.0;
  4. let deltaK = parseInt($("#rangeK").val()) / 100.0;
  5. for (let i = 0; i < dst.length; i++) {
  6.   let r = src[i] & 0xFF;
  7.   let g = (src[i] >> 8) & 0xFF;
  8.   let b = (src[i] >> 16) & 0xFF;
  9.  
  10.   // RGB to CMYK
  11.   let k = 1 - (Math.max(r, g, b) / 255.0);
  12.   let c = (1 - (r / 255.0) - k) / (1 - k);
  13.   let m = (1 - (g / 255.0) - k) / (1 - k);
  14.   let y = (1 - (b / 255.0) - k) / (1 - k);
  15.  
  16.   c += deltaC;
  17.   m += deltaM;
  18.   y += deltaY;
  19.   k += deltaK;
  20.   if (c > 1) c = 1;
  21.   else if (c < 0) c = 0;
  22.   if (m > 1) m = 1;
  23.   else if (m < 0) m = 0;
  24.   if (y > 1) y = 1;
  25.   else if (y < 0) y = 0;
  26.   if (k > 1) k = 1;
  27.   else if (k < 0) k = 0;
  28.  
  29.   // CMYK to RGB
  30.   r = Math.floor(255 * (1 - c) * (1 - k));
  31.   g = Math.floor(255 * (1 - m) * (1 - k));
  32.   b = Math.floor(255 * (1 - y) * (1 - k));
  33.  
  34.   dst[i] = (src[i] & 0xFF000000) | (b << 16) | (g << 8) | r;
  35. }

See the Pen Image processing 5.3. CMYK correction by aNNiMON (@aNNiMON) on CodePen.


Для наглядности предлагаю сначала выкрутить все компоненты в -100. Получится белый "лист". Теперь, если постепенно поднимать интенсивность чёрного K, будет проявляться чёрно-белое изображение. Вот пример при C=M=Y=-100, K=0:
cmyk_-100_-100_-100_0.jpg

Постепенно добавляя "краску", будет получаться цветное изображение. C=-12 M=-43 Y=K=0:
cmyk_-12_-43_0_0.jpg

C=-24 M=-18 Y=3 K=-28:
cmyk_-24_-18_3_-28.jpg


Цветовая модель HSLМодель HSL построена на более понятном человеку восприятии цветов и использует такие составляющие: hue – оттенок, saturation – насыщенность и lightness – светлота. Действительно, нам проще сказать "сделай фотографию немного светлее и чуть более насыщенной", чем "увеличь красный и зелёный, а синий немного убавь".

Кроме HSL существует схожая модель HSV (или HSB) – hue, saturation, value (или brightness) – яркость. Отличаются они тем, что максимальное значение третьей компоненты у HSL даёт белый цвет, а у HSB/HSV — яркий цвет.
hsvl.png

HSB/HSV можно представить как конус. Оттенок задаётся как угол на окружности, насыщенность как отдалённость от центра на этой окружности, а яркость как высота. Вершиной конуса является чёрный цвет.
HSV_cone.png

  1. function rgbToHsl(r, g, b) {
  2.   let max = Math.max(r, g, b);
  3.   let min = Math.min(r, g, b);
  4.   let l = (max + min) / 2;
  5.  
  6.   if (max == min) {
  7.     return [0, 0, l];
  8.   }
  9.   let h, s;
  10.   let d = max - min;
  11.   if (l > 0.5) {
  12.     s = d / (2 - max - min);
  13.   } else {
  14.     s = d / (max + min);
  15.   }
  16.   switch (max) {
  17.     case r:
  18.       h = (g - b) / d + (g < b ? 6 : 0);
  19.       break;
  20.     case g:
  21.       h = (b - r) / d + 2;
  22.       break;
  23.     case b:
  24.       h = (r - g) / d + 4;
  25.       break;
  26.   }
  27.   h /= 6;
  28.   return [h, s, l];
  29. }
  30.  
  31. function hue2rgb(p, q, t) {
  32.   if (t < 0) t += 1;
  33.   else if (t > 1) t -= 1;
  34.   if (t < 1/6) return p + (q - p) * 6 * t;
  35.   if (t < 1/2) return q;
  36.   if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
  37.   return p;
  38. }
  39.  
  40. function hslToRgb(h, s, l) {
  41.   if (s == 0) {
  42.     return [l, l, l];
  43.   }
  44.   let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
  45.   let p = 2 * l - q;
  46.  
  47.   let r = hue2rgb(p, q, h + 1/3);
  48.   let g = hue2rgb(p, q, h);
  49.   let b = hue2rgb(p, q, h - 1/3);
  50.   return [r, g, b];
  51. }

See the Pen Image processing 5.4. HSL correction by aNNiMON (@aNNiMON) on CodePen.


Оригинал:
city.jpg

H=0 S=67 L=-3:
city_hsl_0_67_-3.png

H=75 S=-39 L=0:
city_hsl_75_39_0.png
+8   8   0
367