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

от
Работа с графикой   image processing, обработка изображений, javascript, контрастность, насыщенность, гамма, saturation, brightness, gamma correction, contrast

logo.pngРазберём, пожалуй, самые основные параметры коррекции изображений: яркость, насыщенность (без перехода к модели HSV), контрастность и гамму.

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

ЯркостьЕё мы уже рассматривали, просто вспомним ещё раз.

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


shot-20190310T183414.png


НасыщенностьДля регулировки насыщенности не обязательно переходить к цветовой модели HSV, менять значения и затем снова возвращаться к модели RGB. Можно обойтись обычными расчётами разницы цветовых компонент и значения серого:
  1. for (let i = 0; i < dst.length; i++) {
  2.   let r = src[i] & 0xFF;
  3.   let g = (src[i] >> 8) & 0xFF;
  4.   let b = (src[i] >> 16) & 0xFF;
  5.   let gray = (r * 0.2126 + g * 0.7152 + b * 0.0722);
  6.  
  7.   r += (r - gray) * value / 255;
  8.   g += (g - gray) * value / 255;
  9.   b += (b - gray) * value / 255;
  10.  
  11.   if (r > 255) r = 255;
  12.   else if (r < 0) r = 0;
  13.   if (g > 255) g = 255;
  14.   else if (g < 0) g = 0;
  15.   if (b > 255) b = 255;
  16.   else if (b < 0) b = 0;
  17.  
  18.   dst[i] = (src[i] & 0xFF000000) | (b << 16) | (g << 8) | r;
  19. }

See the Pen Image processing 6.2. Saturation by aNNiMON (@aNNiMON) on CodePen.

В коде примера я изменил value / 255 на value / max, где max = (value < 0) ? 255 : 128.
Сделано это лишь для того, чтобы повысить максимальную насыщенность. Попробуйте оба варианта, либо уменьшите 128 и выкрутите насыщенность на максимум.
В отличие от перехода к HSV, этот способ даёт больше точности и плавности. В Photoshop есть коррекция Вибрация, которая делает так же. Поэтому, не советую использовать в фотошопе Цветовой тон/Насыщенность только лишь для изменения насыщенности.

shot-20190310T184214.png


КонтрастностьКонтрастность это разница между максимальной и минимальной яркостью на изображении.
Давайте ещё раз посмотрим на формулу подсчёта значения цветовых компонент при изменении насыщенности из предыдущего примера:
  1. let gray = (r * 0.2126 + g * 0.7152 + b * 0.0722);
  2. r += (r - gray) * value / 255;
  3. g += (g - gray) * value / 255;
  4. b += (b - gray) * value / 255;
А что будет, если подсчитать значение серого не для одного пикселя, а для всего изображения?
  1. let gray = 0;
  2. for (let i = 0; i < dst.length; i++) {
  3.   let r = src[i] & 0xFF;
  4.   let g = (src[i] >> 8) & 0xFF;
  5.   let b = (src[i] >> 16) & 0xFF;
  6.   gray += (r * 0.2126 + g * 0.7152 + b * 0.0722);
  7. }
  8. gray /= dst.length;
  9.  
  10. for (let i = 0; i < dst.length; i++) {
  11.   let r = src[i] & 0xFF;
  12.   let g = (src[i] >> 8) & 0xFF;
  13.   let b = (src[i] >> 16) & 0xFF;
  14.  
  15.   r += (r - gray) * delta / 255;
  16.   g += (g - gray) * delta / 255;
  17.   b += (b - gray) * delta / 255;
  18.  
  19.   if (r > 255) r = 255;
  20.   else if (r < 0) r = 0;
  21.   if (g > 255) g = 255;
  22.   else if (g < 0) g = 0;
  23.   if (b > 255) b = 255;
  24.   else if (b < 0) b = 0;
  25.  
  26.   dst[i] = (src[i] & 0xFF000000) | (b << 16) | (g << 8) | r;
  27. }
Мы получим регулировку контрастности!

See the Pen Image processing 6.3. Contrast by aNNiMON (@aNNiMON) on CodePen.


shot-20190310T184749.jpg


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

gamma.png

Применение гамма-коррекции как раз и позволяет перейти от цифрового представления яркости к яркости, правильно воспринимаемой человеком, и наоборот.

Обычно для гамма-коррекции применяется простая степенная функция:
  1. let gamma = parseInt($("#rangeGamma").val()); // 0.1 ~ 6.0
  2. let level =  1.0 / (gamma / 100.0);
  3.  
  4. let pow = [];
  5. for (let i = 0; i < 256; i++) {
  6.   let value = (255 * Math.pow(i / 255.0, level) + 0.5);
  7.   if (value > 255) value = 255;
  8.   else if (value < 0) value = 0;
  9.   else value = Math.floor(value);
  10.   pow.push(value);
  11. }
  12.  
  13. for (let i = 0; i < dst.length; i++) {
  14.   let r = src[i] & 0xFF;
  15.   let g = (src[i] >> 8) & 0xFF;
  16.   let b = (src[i] >> 16) & 0xFF;
  17.  
  18.   r = pow[r];
  19.   g = pow[g];
  20.   b = pow[b];
  21.  
  22.   dst[i] = (src[i] & 0xFF000000) | (b << 16) | (g << 8) | r;
  23. }
Так как значений яркости каждой компоненты пикселя может быть лишь 256, то для ускорения обработки можно построить таблицу, а затем из неё брать значения.

See the Pen Image processing 6.4. Gamma by aNNiMON (@aNNiMON) on CodePen.


Благодаря гамма-коррекции, на тёмных фотографиях могут проявиться незаметные до этого детали.

shot-20190310T185425.png

shot-20190310T190819.jpg
+7   7   0
570