Обработка изображений OpenCV

Obrabotka Izobrazenij Opencv



В этой статье мы собираемся изучить методы обработки изображений. Мы рассмотрим некоторые фундаментальные, но важные темы компьютерного зрения и машинного обучения. Эти фундаментальные методы обработки изображений могут решать сложные проблемы, такие как наборы данных. В результате существует шесть основных шагов обработки изображений, которые перечислены ниже:
  1. Перевод изображения
  2. Поворот изображения
  3. Арифметика изображений
  4. Переворот изображения
  5. Обрезка изображения
  6. Изменение размера изображения

Теперь мы подробно объясним все вышеупомянутые темы обработки изображений.

1. Перевод изображения

Преобразование изображения — это метод обработки изображения, который помогает нам перемещать изображение по осям x и y. Мы можем перемещать изображение вверх, вниз, вправо, влево или в любую комбинацию.







Мы можем определить матрицу перевода с помощью символа M и представить ее в математической форме, как показано ниже:





Мы можем понять концепцию перевода изображения с помощью этой программы.





Код Python: Мы сохраним имя следующей программы как перевести.py .

# импортировать необходимые пакеты

импорт пустышка как например

импорт разбор аргументов

импорт имутил

импорт cv2

# реализуем парсер аргументов

ap_obj знак равно анализ аргументов. АргументПарсер ( )

ap_obj. add_argument ( '-к' , '--изображение' , обязательный знак равно Истинный ,

помощь знак равно 'расположение файла изображения' )

аргументы знак равно чья ( ap_obj. parse_args ( ) )

# загрузить изображение и показать на экране

изображение знак равно cv2. прочитывать ( аргументы [ 'изображение' ] )

cv2. им-шоу ( 'Исходное_изображение' , изображение )

# Перевод изображения представляет собой матрицу NumPy, которая приведена ниже:

# [[1, 0, сдвигX], [0, 1, сдвигY]]

# Мы собираемся использовать приведенную выше матрицу NumPy для смещения изображений вдоль

# Направления оси x и оси y. Для этого нам нужно просто передать значения пикселей.

# В этой программе мы сдвинем изображение на 30 пикселей вправо

# и 70 пикселей вниз.

translation_mat знак равно например поплавок32 ( [ [ 1 , 0 , 30 ] , [ 0 , 1 , 70 ] ] )

image_translation знак равно cv2. warpAffine ( изображение , translation_mat ,

( изображение. форма [ 1 ] , изображение. форма [ 0 ] ) )

cv2. им-шоу ( «Перевод изображения вниз и вправо» , image_translation )

# теперь мы собираемся использовать приведенную выше матрицу NumPy для смещения изображений вдоль

# Направления оси X (влево) и оси Y (вверх).

# Здесь мы сдвинем изображения на 50 пикселей влево

# и 90 пикселей вверх.

translation_mat знак равно например поплавок32 ( [ [ 1 , 0 , - 50 ] , [ 0 , 1 , - 90 ] ] )

image_translation знак равно cv2. warpAffine ( изображение , translation_mat ,

( изображение. форма [ 1 ] , изображение. форма [ 0 ] ) )

cv2. им-шоу ( «Перевод изображения вверх и влево» , image_translation )

cv2. ключ ожидания ( 0 )

Строки с 1 по 5: Мы импортируем все необходимые пакеты для этой программы, такие как OpenCV, argparser и NumPy. Пожалуйста, обратите внимание, что есть еще одна библиотека imutils. Это не пакет OpenCV. Это просто библиотека, которая легко покажет ту же обработку изображений.



Библиотека imutils не будет автоматически включаться при установке OpenCV. Итак, чтобы установить imutils, мы должны использовать следующий метод:

пип установить imutils

Строки с 8 по 15: Мы создали наш агрпарсер и загрузили наш образ.

Строки 24-25: В этом разделе программы происходит перевод. Матрица перевода сообщает нам, на сколько пикселей изображение будет перемещено вверх или вниз, влево или вправо. Поскольку OpenCV требует, чтобы значение матрицы было в массиве с плавающей запятой, матрица перевода принимает значения в массивах с плавающей запятой.

Первая строка матрицы перевода выглядит так:

Эта строка матрицы предназначена для оси X. Значение т Икс будет решать, будет ли изображение смещено влево или вправо. Если мы передаем отрицательное значение, то это означает, что изображение будет смещено влево, а если значение положительное, то это означает, что изображение будет сдвинуто вправо.

Теперь определим вторую строку матрицы следующим образом:

Эта строка матрицы предназначена для оси Y. Значение т Д будет решать, будет ли изображение сдвинуто вверх или вниз. Если мы передаем отрицательное значение, то это означает, что изображение будет сдвинуто вверх, а если значение положительное, то это означает, что изображение будет сдвинуто вниз.

В предыдущей программе в строке 24 мы определяем t Икс = 30 и т Д = 70. Таким образом, мы перемещаем изображение на 30 пикселей вправо и на 70 пикселей вниз.

Но основной процесс перевода изображения происходит в строке 25, где мы определяем матрицу перевода cv2.warpAffine . В эту функцию мы передаем три параметра: первый параметр — это изображение, второй параметр — матрица перевода, а третий параметр — размер изображения.

Строка 27: Строка 27 отобразит результат на выходе.

Теперь мы реализуем другую матрицу перевода для левой и верхней стороны. Для этого мы должны определить отрицательные значения.

Строки с 33 по 34: В предыдущей программе в строке 33 мы определяем t Икс = -50 и т Д = -90. Итак, мы перемещаем изображение на 50 пикселей влево и на 90 пикселей вверх. Но основной процесс перевода изображения происходит в строке 34, где мы определяем матрицу перевода cv2.warpAffine .

Строка 36 : Строка 36 будет отображать результат, как показано в выводе.

Чтобы запустить предыдущий код, мы должны указать путь к изображению, как указано ниже.

Вывод: python translate.py – изображение белка.jpg

Теперь мы реализуем ту же программу перевода изображений, используя имутил библиотека. Эта библиотека очень проста в использовании для обработки изображений. В этой библиотеке нам не нужно думать о cv2.warpAffine потому что эта библиотека позаботится об этом. Итак, давайте реализуем эту программу перевода изображений, используя библиотеку imutils.

Код Python: Мы сохраним имя следующей программы как translate_imutils.py .

# импортируем необходимые пакеты

импорт пустышка как например

импорт разбор аргументов

импорт имутил

импорт cv2

# Эта функция реализует перевод изображения и

# возвращает переведенное изображение вызывающей функции.

деф переводить ( изображение , Икс , Д ) :

матрица_перевода знак равно например поплавок32 ( [ [ 1 , 0 , Икс ] , [ 0 , 1 , Д ] ] )

image_translation знак равно cv2. warpAffine ( изображение , матрица_перевода ,

( изображение. форма [ 1 ] , изображение. форма [ 0 ] ) )

возвращаться image_translation

# создаем анализатор аргументов и анализируем аргументы

ап знак равно анализ аргументов. АргументПарсер ( )

ап. add_argument ( '-я' , '--изображение' , обязательный знак равно Истинный , помощь знак равно «Путь к образу» )

аргументы знак равно чья ( ап. parse_args ( ) )

# загрузить изображение и вывести на экран

изображение знак равно cv2. прочитывать ( аргументы [ 'изображение' ] )

cv2. им-шоу ( 'Исходное_изображение' , изображение )

image_translation знак равно иутил. переводить ( изображение , 10 , 70 )

cv2. им-шоу ( «Перевод изображения вправо и влево» ,

image_translation )

cv2. ключ ожидания ( 0 )

Строки с 9 по 13: В этом разделе программы происходит перевод. Матрица перевода сообщает нам, на сколько пикселей изображение будет перемещено вверх или вниз, влево или вправо.

Эти строки уже были объяснены, но сейчас мы создадим функцию с именем translate() и отправим в нее три различных параметра. Само изображение служит первым параметром. Значения x и y матрицы перевода соответствуют второму и третьему параметрам.

Запись : нет необходимости определять эту функцию перевода внутри программы, поскольку она уже включена в пакет библиотеки imutils. Я использовал его в программе для простоты объяснения. Мы можем вызвать эту функцию непосредственно с помощью imutils, как показано в строке 24.

Строка 24: Предыдущая программа покажет, что в строке 24 мы определяем tx = 10 и ty = 70. Таким образом, мы перемещаем изображение на 10 пикселей вправо и на 70 пикселей вниз.

В этой программе нам не нужны никакие функции cv2.warpAffine, поскольку они уже находятся внутри пакета библиотеки imutils.

Чтобы запустить предыдущий код, мы должны указать путь к изображению, как показано ниже:

Вывод:

Python imutils. пи --изображение белка. jpg

2. Поворот изображения

Мы рассмотрели, как переводить (т. е. сдвигать) изображение вверх, вниз, влево и вправо в предыдущем уроке (или любую комбинацию). Далее мы обсудим вращение в связи с обработкой изображений.

Изображение поворачивается на угол тета в процессе, известном как вращение. Угол, на который мы поворачиваем изображение, будет представлен тета. Кроме того, впоследствии я предоставлю удобную функцию поворота, чтобы упростить поворот изображений.

Подобно перемещению и, что неудивительно, повороту на угол, тета определяется построением матрицы M в следующем формате:

Эта матрица может вращать вектор тета-градусов (против часовой стрелки) вокруг начала координат заданной (x, y)-декартовой плоскости. Обычно в этом сценарии начало координат было бы центром изображения, но на самом деле мы могли бы обозначить любую случайную точку (x, y) в качестве нашего центра вращения.

Затем повернутое изображение R создается из исходного изображения I с помощью простого матричного умножения: R = IM

OpenCV, с другой стороны, дополнительно предлагает возможность (1) масштабирования (т.е. изменения размера) изображения и (2) предлагает произвольный центр вращения для выполнения вращения вокруг.

Наша модифицированная матрица вращения M показана ниже:

Начнем с открытия и создания нового файла с именем rotate.py :

# импортируем необходимые пакеты

импорт пустышка как например

импорт разбор аргументов

импорт имутил

импорт cv2

# создание объекта argumentsparser и разбор аргумента

apobj знак равно анализ аргументов. АргументПарсер ( )

апобж. add_argument ( '-к' , '--изображение' , обязательный знак равно Истинный , помощь знак равно 'путь изображения' )

аргументы знак равно чья ( апобж. parse_args ( ) )

изображение знак равно cv2. прочитывать ( аргументы [ 'изображение' ] )

cv2. им-шоу ( 'Исходное_изображение' , изображение )

# Вычислить центр изображения, используя размеры изображения.

( рост , ширина ) знак равно изображение. форма [ : 2 ]

( центрX , центр Y ) знак равно ( ширина / 2 , рост / 2 )

# Теперь, используя cv2, мы повернем изображение на 55 градусов, чтобы

# определяем матрицу поворота с помощью getRotationMatrix2D()

вращениеМатрица знак равно cv2. getRotationMatrix2D ( ( центрX , центрY ) , 55 , 1,0 )

повернутое изображение знак равно cv2. warpAffine ( изображение , вращениеМатрица , ( ширина , рост ) )

cv2. им-шоу ( 'Повернуто изображение на 55 градусов' , повернутое изображение )

cv2. ключ ожидания ( 0 )

# Теперь изображение будет повернуто на -85 градусов.

вращениеМатрица знак равно cv2. getRotationMatrix2D ( ( центрX , центр Y ) , - 85 , 1,0 )

повернутое изображение знак равно cv2. warpAffine ( изображение , вращениеМатрица , ( ширина , рост ) )

cv2. им-шоу ( 'Повернуто изображение на -85 градусов' , повернутое изображение )

cv2. ключ ожидания ( 0 )

Строки с 1 по 5: Мы импортируем все необходимые пакеты для этой программы, такие как OpenCV, argparser и NumPy. Пожалуйста, обратите внимание, что есть еще одна библиотека imutils. Это не пакет OpenCV. Это просто библиотека, которая будет использоваться для простой демонстрации обработки одного и того же изображения.

Библиотека imutils не будет автоматически включаться при установке OpenCV. OpenCV устанавливает imutils. Мы должны использовать следующий метод:

пип установить imutils

Строки с 8 по 14: Мы создали наш агрпарсер и загрузили наш образ. В этом argparser мы используем только один аргумент изображения, который сообщит нам путь к изображению, которое мы будем использовать в этой программе для демонстрации поворота.

При вращении изображения мы должны определить точку вращения. В большинстве случаев вы захотите повернуть изображение вокруг его центра, но OpenCV позволяет вместо этого выбрать любую случайную точку. Давайте просто повернем изображение вокруг его центра.

Строки с 17 по 18 возьмите ширину и высоту изображения соответственно, а затем разделите каждое измерение на два, чтобы установить центр изображения.

Мы создаем матрицу для поворота изображения так же, как мы определяли матрицу для перемещения изображения. Мы просто позвоним cv2.getRotationMatrix2D в строке 22, а не создавать матрицу вручную с помощью NumPy (что может быть немного громоздким).

cv2.getRotationMatrix2D функция требует три параметра. Первый ввод — желаемый угол поворота (в данном случае центр изображения). Затем тета используется, чтобы указать, на сколько градусов (против часовой стрелки) мы будем поворачивать изображение. Здесь мы повернем изображение на 45 градусов. Последний параметр связан с размером изображения.

Несмотря на то, что мы еще не обсуждали масштабирование изображения, вы можете указать здесь число с плавающей запятой, где 1.0 означает, что изображение должно использоваться в исходных пропорциях. Однако, если вы введете значение 2,0, изображение увеличится вдвое. Число 0,5 уменьшает размер изображения таким образом.

Строка 22-23: Получив нашу матрицу вращения M из cv2.getRotationMatrix2D функцию, мы поворачиваем наше изображение с помощью cv2.warpAffine в строке 23. Первым входом функции является изображение, которое мы хотим повернуть. Затем определяются ширина и высота нашего выходного изображения вместе с нашей матрицей поворота M. Затем в строке 23 изображение поворачивается на 55 градусов.

Вы можете заметить, что наше изображение было повернуто.

Строки с 28 по 30 составляют второе вращение. Строки 22–23 кода идентичны, за исключением того, что на этот раз мы поворачиваем на -85 градусов, а не на 55.

До этого момента мы просто вращали изображение вокруг его центра. Что, если бы мы захотели повернуть изображение вокруг случайной точки?

Начнем с открытия и создания нового файла с именем повернуть.py:

# импортируем необходимые пакеты

импорт пустышка как например

импорт разбор аргументов

импорт имутил

импорт cv2

# создание объекта argumentsparser и разбор аргумента

ap_obj знак равно анализ аргументов. АргументПарсер ( )

ap_obj. add_argument ( '-к' , '--изображение' , обязательный знак равно Истинный , помощь знак равно 'путь изображения' )

аргумент знак равно чья ( ap_obj. parse_args ( ) )

# загрузить изображение и вывести на экран

изображение знак равно cv2. прочитывать ( аргумент [ 'изображение' ] )

cv2. им-шоу ( 'Исходное_изображение' , изображение )

# Вычислить центр изображения, используя размеры изображения.

( рост , ширина ) знак равно изображение. форма [ : 2 ]

( центрX , центрY ) знак равно ( ширина / 2 , рост / 2 )

# Теперь, используя cv2, мы повернем изображение на 55 градусов, чтобы

# определяем матрицу поворота с помощью getRotationMatrix2D()

вращениеМатрица знак равно cv2. getRotationMatrix2D ( ( центрX , центрY ) , 55 , 1,0 )

повернутое изображение знак равно cv2. warpAffine ( изображение , вращениеМатрица , ( ширина , рост ) )

cv2. им-шоу ( 'Повернуто изображение на 55 градусов' , повернутое изображение )

cv2. ключ ожидания ( 0 )

# Теперь изображение будет повернуто на -85 градусов.

вращениеМатрица знак равно cv2. getRotationMatrix2D ( ( центрX , центр Y ) , - 85 , 1,0 )

повернутое изображение знак равно cv2. warpAffine ( изображение , вращениеМатрица , ( ширина , рост ) )

cv2. им-шоу ( 'Повернуто изображение на -85 градусов' , повернутое изображение )

cv2. ключ ожидания ( 0 )

# поворот изображения из произвольной точки, а не из центра

вращениеМатрица знак равно cv2. getRotationMatrix2D ( ( центрX - 40 , центр Y - 40 ) , 55 , 1,0 )

повернутое изображение знак равно cv2. warpAffine ( изображение , вращениеМатрица , ( ширина , рост ) )

cv2. им-шоу ( 'Поворот изображения из произвольных точек' , повернутое изображение )

cv2. ключ ожидания ( 0 )

Строки с 34 по 35: Теперь этот код должен показаться довольно обычным для вращения объекта. Чтобы повернуть изображение вокруг точки на 40 пикселей влево и на 40 пикселей выше ее центра, мы указываем cv2.getRotationMatrix2D функцию, чтобы обратить внимание на ее первый параметр.

Изображение, полученное при применении этого поворота, показано ниже:

Мы можем ясно видеть, что центром вращения теперь является (x, y)-координата, которая находится на 40 пикселей левее и на 40 пикселей выше вычисленного центра изображения.

3. Арифметика изображений

На самом деле арифметика изображений — это просто сложение матриц с несколькими дополнительными ограничениями на типы данных, которые мы рассмотрим позже.

Давайте на минутку пробежимся по некоторым основам линейной алгебры.

Рассмотрите возможность объединения следующих двух матриц:

Какой результат даст сложение матриц? Простой ответ — это сумма элементов матрицы, поэлементно:

Достаточно просто, не так ли?

В настоящее время мы все понимаем основные операции сложения и вычитания. Однако при работе с изображениями мы должны помнить об ограничениях, налагаемых нашим цветовым пространством и типом данных.

Пиксели в изображениях RGB, например, находятся между [0, 255]. Что произойдет, если мы попытаемся добавить 10 к пикселю с интенсивностью 250, глядя на него?

Мы получили бы значение 260, если бы применяли стандартные арифметические принципы. 260 не является допустимым значением, так как изображения RGB представлены в виде 8-битных целых чисел без знака.

Так что же должно произойти? Должны ли мы запустить проверку, чтобы убедиться, что ни один пиксель не находится за пределами диапазона [0, 255], обрезав каждый пиксель, чтобы он имел значение от 0 до 255?

Или мы «оборачиваемся» и выполняем операцию по модулю? В соответствии с правилами модуля прибавление 10 к 255 даст просто значение 9.

Как следует обрабатывать сложения и вычитания изображений за пределами диапазона [0, 255]?

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

Но помните, что между добавлением в OpenCV и добавлением в NumPy есть различия. Модульная арифметика и «обход» будут выполняться NumPy. Напротив, OpenCV будет выполнять отсечение и следить за тем, чтобы значения пикселей никогда не покидали диапазон [0, 255].

Начнем с создания нового файла с именем арифметика.py и открывая его:

# python арифметика.py --image squirrel.jpg

# импортируем необходимые пакеты

импорт пустышка как например

импорт разбор аргументов

импорт имутил

импорт cv2

# создание объекта argumentsparser и разбор аргумента

apObj знак равно анализ аргументов. АргументПарсер ( )

apObj. add_argument ( '-к' , '--изображение' , обязательный знак равно Истинный , помощь знак равно 'путь изображения' )

аргументы знак равно чья ( apObj. parse_args ( ) )

изображение знак равно cv2. прочитывать ( аргументы [ 'изображение' ] )

cv2. им-шоу ( 'Исходное_изображение' , изображение )

'''

Значения наших пикселей будут в диапазоне [0, 255]

поскольку изображения представляют собой массивы NumPy, которые хранятся как 8-битные целые числа без знака.

При использовании таких функций, как cv2.add и cv2.subtract, значения будут обрезаны.

в этот диапазон, даже если они добавляются или вычитаются за пределами

[0, 255] диапазон. Вот иллюстрация:

'''


Распечатать ( 'максимум 255: {}' . формат ( ул ( cv2. Добавлять ( например uint8 ( [ 201 ] ) ,

например uint8 ( [ 100 ] ) ) ) ) )

Распечатать ( 'минимум 0: {}' . формат ( ул ( cv2. вычесть ( например uint8 ( [ 60 ] ) ,

например uint8 ( [ 100 ] ) ) ) ) )

'''

При выполнении арифметических операций с этими массивами с помощью NumPy,

значение будет перенесено, а не обрезано до

[0, 255]диапазон. При использовании изображений важно соблюдать это

в уме.

'''


Распечатать ( 'обернуть: {}' . формат ( ул ( например uint8 ( [ 201 ] ) + напр. uint8 ( [ 100 ] ) ) ) )

Распечатать ( 'обернуть: {}' . формат ( ул ( например uint8 ( [ 60 ] ) - напр. uint8 ( [ 100 ] ) ) ) )

'''

Давайте умножим яркость каждого пикселя нашего изображения на 101.

Для этого мы генерируем массив NumPy того же размера, что и наша матрица,

заполненный единицами, и умножьте его на 101, чтобы получить массив, заполненный

со 101с. Наконец, мы объединяем два изображения.

Вы заметите, что изображение стало «ярче».

'''


Матрица знак равно например те ( изображение. форма , тип знак равно 'uint8' ) * 101

image_added знак равно cv2. Добавлять ( изображение , Матрица )

cv2. им-шоу ( 'Добавлен результат изображения' , image_added )

#Подобным образом мы можем сделать наше изображение темнее, взяв

# 60 от всех пикселей.

Матрица знак равно например те ( изображение. форма , тип знак равно 'uint8' ) * 60

image_subtracted знак равно cv2. вычесть ( изображение , Матрица )

cv2. им-шоу ( «Вычитанный результат изображения» , image_subtracted )

cv2. ключ ожидания ( 0 )

Строки с 1 по 16 будет использоваться для выполнения нашего обычного процесса, который влечет за собой импорт наших пакетов, настройку нашего парсера аргументов и загрузку нашего изображения.

Помните, как я ранее обсуждал разницу между добавлением OpenCV и NumPy? Теперь, когда мы подробно рассмотрели это, давайте рассмотрим конкретный случай, чтобы убедиться, что мы его поняли.

Два 8-битных целочисленных массива NumPy без знака определены на строка 26 . Значение 201 — единственный элемент в первом массиве. Хотя во втором массиве находится только один член, его значение равно 100. Затем значения добавляются с помощью функции OpenCV cv2.add.

Каким вы ожидаете результат?

В соответствии с общепринятыми арифметическими принципами ответ должен быть 301. Но помните, что мы имеем дело с 8-битными целыми числами без знака, которые могут находиться только в диапазоне [0, 255]. Поскольку мы используем метод cv2.add, OpenCV обрабатывает отсечение и гарантирует, что добавление возвращает только максимальный результат 255.

Первая строка листинга ниже показывает результат выполнения этого кода:

арифметика. пи

максимум 255 : [ [ 255 ] ]

Сумма действительно дала число 255.

После этого строка 26 использует cv2.subtract для выполнения вычитания. Еще раз мы определяем два массива 8-битных целых чисел без знака NumPy с одним элементом в каждом. Значение первого массива равно 60, тогда как значение второго массива равно 100.

Наша арифметика подсказывает, что вычитание должно привести к значению -40, но OpenCV снова обрабатывает отсечение за нас. Мы обнаруживаем, что значение было обрезано до 0. Наш результат ниже демонстрирует это:

арифметика. пи

минимум 0 : [ [ 0 ] ]

Используя cv2, вычтите 100 из вычитания 60, получив значение 0.

Но что произойдет, если мы используем NumPy вместо OpenCV для выполнения вычислений?

Строки 38 и 39 решить эту проблему.

Во-первых, определяются два 8-битных целочисленных массива NumPy без знака, каждый из которых состоит из одного элемента. Значение первого массива равно 201, тогда как значение второго массива равно 100. Наше сложение будет обрезано, и значение 255 будет возвращено, если мы воспользуемся функцией cv2.add.

NumPy, с другой стороны, «обертывает» и выполняет арифметику по модулю, а не отсечение. NumPy обнуляется, как только достигается значение 255, а затем возобновляет подсчет до тех пор, пока не будет достигнуто 100 шагов. Это подтверждается первой строкой вывода, показанной ниже:

арифметика. пи
обернуть вокруг: [ Четыре пять ]

Затем определяются еще два массива NumPy, один со значением 50, а другой со значением 100. Это вычитание будет обрезано методом cv2.subtract, чтобы вернуть результат 0. Но мы знаем, что вместо отсечения NumPy выполняет арифметика по модулю. Вместо этого процедуры по модулю зацикливаются и начинают обратный отсчет с 255, когда во время вычитания достигается 0. Мы можем видеть это из следующего вывода:

арифметика. пи

обернуть вокруг: [ 207 ]

Еще раз вывод нашего терминала демонстрирует различие между отсечением и переносом:

Крайне важно помнить о желаемом результате при выполнении целочисленной арифметики. Вы хотите, чтобы какие-либо значения за пределами диапазона [0, 255] были обрезаны? После этого используйте встроенные методы арифметики изображений OpenCV.

Вы хотите, чтобы значения переносились, если они находятся за пределами диапазона [0, 255] и арифметических операций по модулю? Затем массивы NumPy просто складываются и вычитаются, как обычно.

Строка 48 определяет одномерный массив NumPy с теми же размерами, что и наше изображение. Еще раз убеждаемся, что наш тип данных — это 8-битные целые числа без знака. Мы просто умножаем нашу матрицу однозначных значений на 101, чтобы заполнить ее значениями 101 вместо 1. Наконец, мы используем функцию cv2.add, чтобы добавить нашу матрицу 100 к исходному изображению. Это увеличивает интенсивность каждого пикселя на 101, а также гарантирует, что любые значения, которые пытаются превысить 255, обрезаются до диапазона [0, 255].

Обратите внимание, что изображение заметно ярче и кажется более «размытым», чем оригинал. Это связано с тем, что мы приближаем пиксели к более ярким цветам, повышая интенсивность их пикселей на 101.

Чтобы вычесть 60 из интенсивности каждого пикселя изображения, мы сначала устанавливаем второй массив NumPy в строке 54, который заполняется 60-ми.

Результаты этого вычитания изображены на следующем изображении:

Предметы вокруг нас кажутся значительно темнее, чем раньше. Это связано с тем, что, вычитая 60 из каждого пикселя, мы перемещаем пиксели в цветовом пространстве RGB в более темные области.

4. Переворот изображения

Подобно вращению, переворот изображения по оси x или y — еще один вариант, предлагаемый OpenCV. Даже если операции переворачивания используются не так часто, знание их невероятно полезно по разным причинам, которые вы можете не сразу увидеть.

Мы разрабатываем классификатор машинного обучения для небольшой стартап-компании, которая стремится идентифицировать лица на изображениях. Чтобы наша система «узнала», что такое лицо, нам понадобится какой-то набор данных с образцами лиц. К сожалению, компания предоставила нам только небольшой набор данных из 40 лиц, и мы не можем собрать больше информации.

Что же нам делать?

Поскольку лицо остается лицом независимо от того, зеркально оно отражено или нет, мы можем перевернуть каждое изображение лица по горизонтали и использовать зеркальные версии в качестве дополнительных обучающих данных.

Этот пример может показаться глупым и искусственным, но это не так. Переворот — это преднамеренная стратегия, используемая сильными алгоритмами глубокого обучения для получения большего количества данных на этапе обучения.

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

Цели:

С использованием cv2.flip функция, вы узнаете, как отразить изображение как по горизонтали, так и по вертикали на этом занятии.

Переворот — это следующая манипуляция с изображением, которую мы будем изучать. Оси x и y изображения могут быть перевернуты или даже обе. Прежде чем мы углубимся в кодирование, лучше сначала взглянуть на результаты переворота изображения. См. изображение, перевернутое по горизонтали, на следующем изображении:


Обратите внимание на то, как наше исходное изображение слева и как изображение было отражено по горизонтали справа.

Начнем с создания нового файла с именем листать.py .

Вы видели пример переворачивания изображения, так что давайте рассмотрим код:

# python flipping.py --image quirrel.jpg

# импортируем необходимые пакеты

импорт разбор аргументов

импорт cv2

# создание объекта парсера аргументов и разбор аргумента

apObj знак равно анализ аргументов. АргументПарсер ( )

apObj. add_argument ( '-я' , '--изображение' , обязательный знак равно Истинный , помощь знак равно 'путь изображения' )

аргумент знак равно чья ( apObj. parse_args ( ) )

изображение знак равно cv2. прочитывать ( аргумент [ 'изображение' ] )

cv2. им-шоу ( 'Оригинал' , изображение )

# горизонтально отразить изображение

изображение перевернуто знак равно cv2. кувырок ( изображение , 1 )

cv2. им-шоу ( «Перевернутое изображение по горизонтали» , изображение перевернуто )

# перевернуть изображение по вертикали

изображение перевернуто знак равно cv2. кувырок ( изображение , 0 )

cv2. им-шоу ( «Перевернутое изображение по вертикали» , изображение перевернуто )

# отражение изображения по обеим осям

изображение перевернуто знак равно cv2. кувырок ( изображение , - 1 )

cv2. им-шоу ( «Перевернуто по горизонтали и вертикали» , изображение перевернуто )

cv2. ключ ожидания ( 0 )

Шаги, которые мы предпринимаем для импорта наших пакетов, анализа наших входных данных и загрузки нашего изображения с диска, обрабатываются в l с 1 по 12 .

Вызывая функцию cv2.flip на Строка 15 , просто перевернуть изображение по горизонтали. Изображение, которое мы пытаемся перевернуть, и специальный код или флаг, указывающий, как перевернуть изображение, являются двумя аргументами, необходимыми для метода cv2.flip.

Значение кода переворота, равное 1, означает, что мы будем вращать изображение вокруг оси Y, чтобы перевернуть его по горизонтали ( Строка 15 ). Если мы укажем флип-код 0, мы хотим повернуть изображение вокруг оси x ( Строка 19 ). Отрицательный флип-код ( Строка 23 ) поворачивает изображение по обеим осям.

Одним из самых простых примеров в этой теме является переворачивание изображения, что является основным.

Далее мы обсудим обрезку изображений и использование фрагментов массива NumPy для извлечения определенных частей изображения.

5. Обрезка изображения

Обрезка, как следует из названия, — это процесс выбора и удаления интересующей области (или просто ROI), представляющей интересующую нас область изображения.

Лицо должно быть вырезано из изображения для приложения для обнаружения лиц. Кроме того, если бы мы создавали скрипт Python для поиска собак на изображениях, мы могли бы захотеть вырезать собаку из изображения, когда мы ее найдем.

Цели: Наша главная цель — ознакомиться и легко использовать нарезку массива NumPy для обрезки областей изображения.

Обрезка : Когда мы обрезаем изображение, наша цель — удалить внешние элементы, которые нас не интересуют. Процесс выбора области интереса часто называют выбором интересующей нас области.

Создайте новый файл с именем обрезать.py , откройте его и добавьте следующий код:

# питон урожая.py

# импортируем необходимые пакеты

импорт cv2

# загрузка изображения и отображение на экране

изображение знак равно cv2. прочитывать ( 'белка.jpg' )

Распечатать ( изображение. форма )

cv2. им-шоу ( 'Оригинал' , изображение )

# Фрагменты массива NumPy используются для быстрой обрезки изображения

# мы собираемся обрезать мордочку белки с изображения

белка знак равно изображение [ 35 : 90 , 35 : 100 ]

cv2. им-шоу ( 'беличье лицо' , белка )

cv2. ключ ожидания ( 0 )

# А теперь мы собираемся обрезать все тело

# белки

белка знак равно изображение [ 35 : 148 , 23 : 143 ]

cv2. им-шоу ( «Тело белки» , белка )

cv2. ключ ожидания ( 0 )

Мы покажем кадрирование в Python и OpenCV, используя изображение, которое мы загружаем с диска на Строки 5 и 6 .

Исходное изображение, которое мы собираемся обрезать

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

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

Мы можем идентифицировать лицо на изображении всего одной строкой кода. Строка 13 , Чтобы извлечь прямоугольную часть изображения, начиная с (35, 35), мы предоставляем фрагменты массива NumPy (90, 100). Может показаться запутанным, что мы подаем урожай с индексами в порядке высоты-сначала и ширины-с, как мы это делаем, но имейте в виду, что OpenCV хранит изображения как массивы NumPy. В результате мы должны указать значения для оси Y перед осью X.

Для обрезки NumPy требуются следующие четыре индекса:

Начало г: Координата Y в начале. В данном случае мы начинаем с y=35.

Конец года: Координата y в конце. Наш урожай остановится, когда y = 90.

Начало x: Координата x начала среза. Обрезка начинается при x=35.

Конец x: Координата конца среза по оси x. При x=100 наш срез закончен.

Точно так же мы вырезаем области (23, 35) и (143, 148) из исходного изображения, чтобы извлечь все тело из изображения на Строка 19 .

Вы можете заметить, что изображение было обрезано, чтобы продемонстрировать только тело и лицо.

6. Изменение размера изображения

Процесс увеличения или уменьшения ширины и высоты изображения называется масштабированием или просто изменением размера. Соотношение сторон, то есть отношение ширины изображения к его высоте, следует учитывать при изменении размера изображения. Пренебрежение соотношением сторон может привести к тому, что масштабированные изображения будут выглядеть сжатыми и искаженными:

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

Техника интерполяции, используемая нашим алгоритмом изменения размера, также должна учитывать цель функции интерполяции — использовать эти окрестности пикселей для увеличения или уменьшения размера изображения.

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

У нас есть исходное изображение слева. Изображение было уменьшено до половины исходного размера в центре, но в остальном «качество» изображения не пострадало. Тем не менее, размер изображения был значительно увеличен справа. Теперь он выглядит «взорванным» и «пиксельным».

Как я уже говорил ранее, вы, как правило, хотите уменьшить размер изображения, а не увеличить его. Уменьшая размер изображения, мы анализируем меньше пикселей и имеем дело с меньшим «шумом», что делает алгоритмы обработки изображений более быстрыми и точными.

Перевод и вращение — это два преобразования изображения, о которых мы говорили до сих пор. Теперь мы рассмотрим, как изменить размер изображения.

Неудивительно, что мы будем изменять размер наших изображений, используя метод cv2.resize. Как я указывал ранее, при использовании этого метода мы должны учитывать соотношение сторон изображения. Но прежде чем мы слишком углубимся в детали, позвольте мне привести вам пример:

# python resize.py --image squirrel.jpg

# импортируем необходимые пакеты

импорт разбор аргументов

импорт cv2

# создание объекта парсера аргументов и разбор аргумента

apObj знак равно анализ аргументов. АргументПарсер ( )

apObj. add_argument ( '-к' , '--изображение' , обязательный знак равно Истинный , помощь знак равно 'путь изображения' )

аргументы знак равно чья ( apObj. parse_args ( ) )

# загрузить изображение и вывести на экран

изображение знак равно cv2. прочитывать ( аргументы [ 'изображение' ] )

cv2. им-шоу ( 'Оригинал' , изображение )

# Чтобы изображение не выглядело перекошенным, соотношение сторон

# необходимо учитывать или деформировать; следовательно, мы выясняем, что

# отношение нового изображения к текущему.

# Давайте сделаем ширину нашего нового изображения 160 пикселей.

аспект знак равно 160,0 / изображение. форма [ 1 ]

измерение знак равно ( 160 , инт ( изображение. форма [ 0 ] * аспект ) )

# эта строка покажет фактические операции изменения размера

измененное изображение знак равно cv2. изменить размер ( изображение , измерение , интерполяция знак равно cv2. INTER_AREA )

cv2. им-шоу ( 'Ширина измененного изображения' , измененное изображение )

# Что, если мы хотим изменить высоту изображения? - с использованием

# тот же принцип, мы можем рассчитать соотношение сторон на основе

# по высоте, а не по ширине. Давайте сделаем масштабирование

# высота изображения 70 пикселей.

аспект знак равно 70,0 / изображение. форма [ 0 ]

измерение знак равно ( инт ( изображение. форма [ 1 ] * аспект ) , 70 )

# выполнить изменение размера

измененное изображение знак равно cv2. изменить размер ( изображение , измерение , интерполяция знак равно cv2. INTER_AREA )

cv2. им-шоу ( 'Высота изображения изменена' , измененное изображение )

cv2. ключ ожидания ( 0 )

Строки 1-14 , После импорта наших пакетов и настройки парсера аргументов мы загрузим и отобразим наше изображение.

Строки 20 и 21: соответствующий код начинается в этих строках. . При изменении размера необходимо учитывать соотношение сторон изображения. Соотношение между шириной и высотой изображения называется соотношением сторон.

Высота ширина это соотношение сторон.

Если мы не примем во внимание соотношение сторон, результаты изменения размера будут искажены.

На Строка 20 , выполняется расчет коэффициента измененного размера. В этой строке кода мы указываем ширину нашего нового изображения как 160 пикселей. Мы просто определяем наше соотношение (aspectratio) как новую ширину (160 пикселей), деленную на старую ширину, к которой мы обращаемся с помощью изображения, чтобы вычислить отношение новой высоты к старой высоте. форма[1].

Новые размеры изображения на Строка 21 можно вычислить теперь, когда мы знаем наше отношение. Опять же, новое изображение будет иметь ширину 160 пикселей. После умножения старой высоты на наш коэффициент и преобразования результата в целое число вычисляется высота. Выполнив эту операцию, мы можем сохранить исходное соотношение сторон изображения.

Строка 24 где изображение действительно изменяется. Изображение, размер которого мы хотим изменить, является первым аргументом, а второй — размерами, которые мы вычислили для нового изображения. Наш метод интерполяции, который представляет собой алгоритм изменения размера фактического изображения, является последним параметром.

Наконец, на Строка 25 , мы отображаем наше масштабированное изображение.

Мы переопределяем наше соотношение (aspectratio) на Строка 31 . Высота нашего нового изображения будет 70 пикселей. Мы делим 70 на исходную высоту, чтобы получить новое отношение высоты к исходной высоте.

Затем мы устанавливаем размеры нового изображения. Новое изображение будет иметь высоту 70 пикселей, которая уже известна. Мы можем еще раз сохранить исходное соотношение сторон изображения, умножив старую ширину на соотношение, чтобы получить новую ширину.

Затем изображение фактически изменяется на Строка 35 , и он отображается на Строка 36.

Здесь мы видим, что мы уменьшили ширину и высоту нашего исходного изображения, сохранив соотношение сторон. Наше изображение выглядело бы искаженным, если бы соотношение сторон не поддерживалось.

Заключение

В этом блоге мы изучили основные концепции обработки изображений. Мы видели перевод изображений с помощью пакета OpenCV. Мы рассмотрели способы перемещения изображения вверх, вниз, вправо и влево. Эти методы очень полезны, когда мы создаем набор данных похожих изображений, чтобы предоставить его в качестве набора данных для обучения, поэтому машина будет видеть разные изображения, даже если они одинаковы. В этой статье вы также узнали, как повернуть изображение вокруг любой точки в декартовом пространстве, используя матрицу вращения. Затем вы узнали, как OpenCV вращает изображения с помощью этой матрицы, и увидели пару иллюстраций вращающихся изображений.

В этом разделе были рассмотрены две основные (но важные) арифметические операции над изображениями: сложение и вычитание. Как видите, сложение и вычитание фундаментальных матриц — это все арифметические операции с изображениями.

Кроме того, мы использовали OpenCV и NumPy для исследования особенностей арифметики изображений. Необходимо помнить об этих ограничениях, иначе вы рискуете получить неожиданные результаты при выполнении арифметических операций над вашими изображениями.

Важно помнить, что, хотя NumPy выполняет операцию модуля и «обходит», OpenCV складывает и вычитает значения за пределами диапазона [0, 255], чтобы соответствовать диапазону. Помните об этом при разработке собственных приложений компьютерного зрения, чтобы избежать поиска хитрых ошибок.

Переворот изображения, несомненно, является одной из самых простых идей, которые мы рассмотрим в этом курсе. Переворот часто используется в машинном обучении для создания большего количества обучающих выборок данных, что приводит к более мощным и надежным классификаторам изображений.

Мы также узнали, как использовать OpenCV для изменения размера изображения. Крайне важно учитывать как метод интерполяции, который вы используете, так и соотношение сторон исходного изображения при изменении размера, чтобы результат не выглядел искаженным.

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