Обработка изображений 2. Изображения. Простая трансформация

от
Работа с графикой    image processing, обработка изображений, javascript, js, flip, mirror, transpose, отражение, поворот

logo2.png
В этой статье реализуем отражение и поворот на 90 и 270 градусов уже для реального изображения. Но прежде, чем это сделать, разберёмся, что вообще из себя представляют изображения и как получить данные о них в JavaScript.

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

Изображения
Здесь всё очень просто: изображение — это набор цветных точек, то есть пикселей. У изображения есть ширина и высота, а также другие параметры, о которых я расскажу потом.
Представить изображение можно в виде двумерного массива, тогда, чтобы получить нижний правый пиксель, просто отнимем единицу от ширины и высоты (помним же, что массивы индексируются с нуля и что обычно сначала получают строку, а потом уже столбец):
pixel = img[height - 1][width - 1].

kenny_2d.png

И как бы такой способ представления не казался удобным, на практике очень часто изображение представляют в виде одномерного массива длиной width*height.

kenny_1d.png
вы только посмотрите, что они сделали с Кенни

Нижний правый пиксель в таком случае получается так: pixel = img[img.length - 1], а чтобы получить пиксель по координате (x, y), нужно сместиться на y строк и x позиций: (y * width + x)

kenny_index.png


Получение пикселей из <img>
Чтобы получить массив пикселей из картинки в теге <img>, нужно:
   1. Получить объект тега img
   2. Получить или создать canvas
   3. Задать размер канваса, чтобы он соответствовал размеру картинки
   4. Отрисовать картинку.

  1. // <img id="image1" src="..." />
  2. // img = getImageData('image1');
  3. function getImageData(el) {
  4.   const canvas = document.createElement('canvas');
  5.   const context = canvas.getContext('2d');
  6.   const img = document.getElementById(el);
  7.   canvas.width = img.width;
  8.   canvas.height = img.height;
  9.   context.drawImage(img, 0, 0);
  10.   return context.getImageData(0, 0, img.width, img.height);
  11. }

Однако, из-за ограничений безопасности, отрисовывать в канвасе можно те картинки, которые поддерживают CORS, либо кодировать изображение в base64. Я в примерах буду пользоваться вторым способом.


Отражение (flip) и поворот на 90° и 270°
Пока что мы не будем раскладывать пиксели на отдельные цветовые компоненты, потому что отражение и поворот картинки это манипуляция с позициями пикселей. Вспоминаем уроки информатики, где были задачи на работу с матрицами, транспонирование, вот это всё.

Отражение по горизонтали. В каждой позиции x рисуем пиксель из позиции (width - x - 1):
  1. for (let y = 0; y < height; y++) {
  2.   for (let x = 0; x < width; x++) {
  3.     dst[y * width + x] = src[y * width + (width - x - 1)];
  4.   }
  5. }

Отражение по вертикали. В каждой позиции y рисуем пиксель из позиции (height - y - 1):
  1. for (let y = 0; y < height; y++) {
  2.   for (let x = 0; x < width; x++) {
  3.     dst[y * width + x] = src[(height - y - 1)  * width + x];
  4.   }
  5. }

Поворот на 90°. Здесь не забываем, что ширина станет высотой, а высота шириной, поэтому нужно создать новый канвас с нужными размерами.
  1. let newWidth = height;
  2. let newHeight = width;
  3. for (let y = 0; y < newHeight; y++) {
  4.   for (let x = 0; x < newWidth; x++) {
  5.     dst[y * newWidth + x] = src[(height - x - 1) * width + y];
  6.   }
  7. }

Поворот на 270°:
  1. let newWidth = height;
  2. let newHeight = width;
  3. for (let y = 0; y < newHeight; y++) {
  4.   for (let x = 0; x < newWidth; x++) {
  5.     dst[y * newWidth + x] = src[x * width + y];
  6.   }
  7. }

Реализацию отражения одновременно по горизонтали и вертикали я оставляю вам в качестве домашнего задания. В следующей статье будет ответ.

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

  • +6
  • views 6501