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

Работать с моделью RGB не всегда удобно. Например, принтер не подчиняется RGB-модели, потому что бумагу ему подают белую и на светлые тона он тратит меньше краски. Поэтому существует множество моделей, призванных решать разного рода задачи. Об основных цветовых моделях и пойдёт речь. А чтобы не было скучно, покрутим немного ползунки.
Содержание:
1. Введение
2. Изображения. Простая трансформация
3. Негатив, извлечение и инверсия каналов
4. Обесцвечивание
5. Цветовые модели
6. Яркость, насыщенность, контрастность, гамма-коррекция
7. Гистограмма
8. Масштабирование изображения
9. Размытие
10. Свёртка
RGB-коррекцияRGB-коррекция применяется в случае, когда нужно слегка подправить фотографию, если на ней слишком много нежелательного оттенка. Например, в результате неправильно выставленного баланса белого фотография может иметь синий или оранжевый оттенок.
Фильтр RGB-коррекции реализуется очень просто. Есть три ползунка с диапазоном от -255 до 255 включительно, по одному на каждую цветовую компоненту.
- <input id="rangeR" type="range" min="-255" max="255" value="0" />
- <input id="rangeG" type="range" min="-255" max="255" value="0" />
- <input id="rangeB" type="range" min="-255" max="255" value="0" />
- let deltaR = parseInt($("#rangeR").val());
- let deltaG = parseInt($("#rangeG").val());
- let deltaB = parseInt($("#rangeB").val());
- for (let i = 0; i < dst.length; i++) {
- let r = src[i] & 0xFF;
- let g = (src[i] >> 8) & 0xFF;
- let b = (src[i] >> 16) & 0xFF;
- r += deltaR;
- g += deltaG;
- b += deltaB;
- if (r > 255) r = 255;
- else if (r < 0) r = 0;
- if (g > 255) g = 255;
- else if (g < 0) g = 0;
- if (b > 255) b = 255;
- else if (b < 0) b = 0;
- dst[i] = (src[i] & 0xFF000000) | (b << 16) | (g << 8) | r;
- }
See the Pen Image processing 5.1. RGB correction by aNNiMON (@aNNiMON) on CodePen.
Оригинал слева и R=41 G=-7 B=-18:


ЯркостьЕсли же регулировать одновременно три значения, то получится фильтр Яркость.
See the Pen Image processing 5.2. Brightness by aNNiMON (@aNNiMON) on CodePen.
Оригинал слева и яркость=-45:


Цветовая модель CMYKCMYK (cyan, magenta, yellow, black) применяется в типографии. Принтеру подают белую бумагу и он, смешивая голубой, пурпурный и жёлтый, получает необходимый цвет. Для экономии цветной краски используется четвёртый компонент K – интенсивность чёрного.
Значения теперь будем указывать в процентах.
- let deltaC = parseInt($("#rangeC").val()) / 100.0;
- let deltaM = parseInt($("#rangeM").val()) / 100.0;
- let deltaY = parseInt($("#rangeY").val()) / 100.0;
- let deltaK = parseInt($("#rangeK").val()) / 100.0;
- for (let i = 0; i < dst.length; i++) {
- let r = src[i] & 0xFF;
- let g = (src[i] >> 8) & 0xFF;
- let b = (src[i] >> 16) & 0xFF;
- // RGB to CMYK
- let k = 1 - (Math.max(r, g, b) / 255.0);
- let c = (1 - (r / 255.0) - k) / (1 - k);
- let m = (1 - (g / 255.0) - k) / (1 - k);
- let y = (1 - (b / 255.0) - k) / (1 - k);
- c += deltaC;
- m += deltaM;
- y += deltaY;
- k += deltaK;
- if (c > 1) c = 1;
- else if (c < 0) c = 0;
- if (m > 1) m = 1;
- else if (m < 0) m = 0;
- if (y > 1) y = 1;
- else if (y < 0) y = 0;
- if (k > 1) k = 1;
- else if (k < 0) k = 0;
- // CMYK to RGB
- r = Math.floor(255 * (1 - c) * (1 - k));
- g = Math.floor(255 * (1 - m) * (1 - k));
- b = Math.floor(255 * (1 - y) * (1 - k));
- dst[i] = (src[i] & 0xFF000000) | (b << 16) | (g << 8) | r;
- }
See the Pen Image processing 5.3. CMYK correction by aNNiMON (@aNNiMON) on CodePen.
Для наглядности предлагаю сначала выкрутить все компоненты в -100. Получится белый "лист". Теперь, если постепенно поднимать интенсивность чёрного K, будет проявляться чёрно-белое изображение. Вот пример при C=M=Y=-100, K=0:

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

C=-24 M=-18 Y=3 K=-28:

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

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

- function rgbToHsl(r, g, b) {
- let max = Math.max(r, g, b);
- let min = Math.min(r, g, b);
- let l = (max + min) / 2;
- if (max == min) {
- return [0, 0, l];
- }
- let h, s;
- let d = max - min;
- if (l > 0.5) {
- s = d / (2 - max - min);
- } else {
- s = d / (max + min);
- }
- switch (max) {
- case r:
- h = (g - b) / d + (g < b ? 6 : 0);
- break;
- case g:
- h = (b - r) / d + 2;
- break;
- case b:
- h = (r - g) / d + 4;
- break;
- }
- h /= 6;
- return [h, s, l];
- }
- function hue2rgb(p, q, t) {
- if (t < 0) t += 1;
- else if (t > 1) t -= 1;
- if (t < 1/6) return p + (q - p) * 6 * t;
- if (t < 1/2) return q;
- if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
- return p;
- }
- function hslToRgb(h, s, l) {
- if (s == 0) {
- return [l, l, l];
- }
- let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
- let p = 2 * l - q;
- let r = hue2rgb(p, q, h + 1/3);
- let g = hue2rgb(p, q, h);
- let b = hue2rgb(p, q, h - 1/3);
- return [r, g, b];
- }
See the Pen Image processing 5.4. HSL correction by aNNiMON (@aNNiMON) on CodePen.
Оригинал:

H=0 S=67 L=-3:

H=75 S=-39 L=0:

6. Яркость, насыщенность, контрастность, гамма-коррекция