Обработка изображений 1. Введение

от
Работа с графикой   image processing, обработка изображений, javascript, js, bitwise, побитовые операции

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

Цвет
В физическом мире цвет представляет собой волну, в то время как в компьютерном мире это чаще всего число. Способов представления цвета много, о некоторых я расскажу в последующих статьях, а сегодня остановимся на самом распространённом — RGB.

В RGB цвет представляется как совмещение яркости трёх компонент: красного цвета (RED), зелёного (GREEN) и синего (BLUE). Минимальная яркость всех трёх компонент даёт нам чёрный цвет; максимальная яркость только красного, разумеется, даёт только красный цвет; максимальная яркость всех трёх компонент даёт белый цвет.

brightness.png

Минимальную и максимальную яркость можно представить разными способами:
  - в процентах (0% — минимум, 100% — максимум)
  - в вещественных числах (0.0 — минимум, 1.0 — максимум)
  - в диапазоне одного байта (0 — минимум, 255 — максимум)


Из всех трёх способов, оптимальным для работы является третий, так как, по сравнению с первым, имеет более широкий диапазон, а по сравнению со вторым, использует целые числа. Именно этот способ представления цвета в RGB и получил широкое распространение.

Прозрачность
Кроме трёх компонент, отвечающих за цвет, существует ещё один компонент, отвечающий за прозрачность. Его ещё называют альфа-каналом (A - Alpha). Минимальное значение (0%, 0.0, 0) означает полностью прозрачный цвет, а максимальное (100%, 1.0, 255) — непрозрачный.


Способы представления цвета
Совмещение трёх (или четырёх) компонент даёт нам информацию о цвете (и прозрачности). Однако, что такое совмещение? В LED индикаторах, это набор из трёх светодиодов (вы уже поняли с какими цветами). В компьютерной графике совмещать компоненты цвета можно различными способами:
  - не совмещать. Пусть себе идут поочерёдно в массиве.
  - совмещать в одно число. 24-битное для RGB и 32-битное, если нужен альфа-канал.

В обоих случаях важно знать порядок следования компонент, потому что бывают разные:
  - RGB. Здесь всё понятно, за красным следует зелёный, а потом синий.
  - ARGB. Как и в предыдущем варианте, только прозрачность идёт первой.
  - RGBA. Сначала цвет, потом прозрачность.
  - BGR. Сначала синий, потом зелёный, потом красный.
  - BGRA. Как и предыдущий, только прозрачность в конце.

Как три (или четыре) компоненты цвета совмещаются в одно число? Вспоминаем побитовые операции.
256 (от 0 до 255 включительно градаций) красного * 256 зелёного * 256 синего = 16777216 цветов.
16777216 цветов * 256 градаций прозрачности = 4294967296 значений.
Именно столько включает в себя 32-битный unsigned int.

Кодируется так:
ARGB: 00000000000000000000000000000000
  1. (alpha << 24) | (red << 16) | (green << 8) | blue
ABGR: 00000000000000000000000000000000
  1. (alpha << 24) | (blue << 16) | (green << 8) | red
RGBA: 00000000000000000000000000000000
  1. (red << 24) | (green << 16) | (blue << 8) | alpha

Для удобства, такой цвет указывают в шестнадцатиричной системе счисления. Например, ARGB:
#AAFF0088: AA (170) - прозрачность, FF (255) - красный, 00 - зелёный, 88 (136) - синий


Работа с цветом в JavaScript
Окунёмся в дебри и будем работать с цветом в JavaScript вообще без использования библиотек jQuery и без самого jQuery.

  1. // Получили canvas, его размеры и контекст
  2. const canvas = document.getElementById('canvas');
  3. const width = canvas.width;
  4. const height = canvas.height;
  5. const ctx = canvas.getContext('2d');
  6. // Получаем данные. Формат: {data: [], width: xx, height: xx}
  7. const img = ctx.getImageData(0, 0, width, height);
  8. const pixels = img.data;
  9.  
  10. // Обрабатываем
  11. // pixels[...] = ...
  12.  
  13. // Заносим данные
  14. ctx.putImageData(img, 0, 0);

По умолчанию, JavaScript вообще не совмещает компоненты, в массиве они идут друг за другом: pixels[0] - красный, pixels[1] - зелёный, pixels[2] - синий, pixels[3] - прозрачность. Этот способ медленный, поэтому рекомендуется использовать другой, где все компоненты совмещены в 32-битный unsigned int в ABGR — Uint32Array.

  1. const canvas = document.getElementById('canvas');
  2. const width = canvas.width;
  3. const height = canvas.height;
  4. const ctx = canvas.getContext('2d');
  5. const img = ctx.getImageData(0, 0, width, height);
  6. const pixels = new Uint32Array(img.data.buffer);
  7.  
  8. // Обрабатываем
  9. // pixels[...] = ...
  10.  
  11. ctx.putImageData(img, 0, 0);

Вот пример закраски канваса красным, зелёным и синим цветом сначала с полной непрозрачностью (A = 255), а потом с полупрозрачностью (A = 128).

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

+7   7   0
643