Reading Time: 7 minutes

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

Весь код, представленный в статье, написан на последней версии Python 3.6 и версии OpenCV 3.3.0. Инструкции по установке OpenCV 3.3.0 вы можете найти у меня на сайте: установка OpenCV 3 на Raspberry Pi 3 Jessie. Весь представленный код может быть запущен как на системах Windows, так и на OSX, и Unix, таких как Raspberry Pi, Banana Pi.

Если вы устанавливали OpenCV 3 в виртуальное окружение, не забудьте перед началом работы войти в него следующими командами:

source ~/.profile
workon cv_python3

Открываем локальный файл в OpenCV 3 Python

Начнем мы с главного – открытия файла. Для примера я использовал кадр из замечательного фильма “Matrix”, или “Матрица”.

Matrix_original_image

Оригинальный кадр из фильма “Матрица”

Скачивайте его на свой компьютер, он понадобиться для дальнейших шагов по изучению OpenCV и Python. Готовы? Поехали дальше!

Загрузим кадр в программу и отобразим его встроенными средствами OpenCV 3 командами:

# добавим необходимый пакет с opencv
import cv2
 
# загружаем изображение и отображаем его
image = cv2.imread("matrix-sunglasses-768x320.jpg")
cv2.imshow("Original image", image)
cv2.waitKey(0)

Выполнение данного кода в Python 3.6 на моем компьютере выводит следующее окно:

Вывод оригинального изображения

Вывод оригинального изображения

Разберем подробно приведенный код:

  • Строка 2: В первой значимой строке мы говорим интерпретатору Python загрузить библиотеку OpenCV
  • Строка 5: Тут мы открываем и читаем файл с жесткого диска. Команда cv2.imread возвращает NumPy массив, который содержит представление данных из изображения.
  • Строки 6-7: Отображение файла встроенными средствами OpenCV. Тут стоит остановиться подробнее: метод для отображения cv2.imshow() принимает в себя два аргумента, первый это название окна, в котором будет отрисовано изображение, второй –  имя переменной, которая хранит данное изображение. Однако выполнение только данной команды отрисует изображение и сразу же закроет программу. Для того, чтобы мы смогли увидеть и работать с изображением, добавим команду cv2.waitKey(0). Данная команда останавливает выполнение скрипта до нажатия клавиши на клавиатуре. Параметр 0 означает что нажатие любой клавиши будет засчитано.

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

Мы загрузили изображение как есть – хорошее начало, но хочется что то сделать с изображением. Сделаем его меньше, чтобы мы могли его использовать как иконку. Мы можем увидеть разрешение оригинального изображения через атрибут изображения shape, который покажет размерность NumPy массива и, таким образом, разрешение снимка:

print(image.shape)

Когда вы выполним код, мы можем увидеть что на терминал выведется (320, 768, 3). Это означает изображение содержит 320 строк, 768 столбцов и 3 канала цвета. Данный формат может показаться знакомым, если вы имели дело в школе или институте с матрицами – там так же сначала писалось количество строк, потом количество столбцов, далее количество матриц.

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

Изображение у шириной целых 768 пикселей, давайте сожмем его до ширины в 200 пикселей:

# Нам надо сохранить соотношение сторон
# чтобы изображение не исказилось при уменьшении
# для этого считаем коэф. уменьшения стороны
final_wide = 200
r = float(final_wide) / image.shape[1]
dim = (final_wide, int(image.shape[0] * r))

# уменьшаем изображение до подготовленных размеров
resized = cv2.resize(image, dim, interpolation = cv2.INTER_AREA)
cv2.imshow("Resize image", resized)
cv2.waitKey(0)

Выполнение кода выведет следующее изображение:

Уменьшенное изображение с шириной 200px

Уменьшенное изображение с шириной 200px

Разберем код:

  • Строки 4-6: Мы задаем итоговую ширину изображения, равную 200px. Далее мы хотим сохранить исходные пропорции изображения, чтобы уменьшить его не искажая. Для этого есть два пути: через коэффициент уменьшения и через коэффициент отношения сторон. В данном случае мы используем отношение новой ширины 200px и исходной 768px = r. Умножение данного числа на исходную высоту даст нам новую высоту изображения. Что мы и используем для создания кортежа с новым разрешением.
  • Строки 9-11: Уменьшаем изображение методом cv2.resize. Данный метод принимает три параметра и возвращает новое изображение. Первый параметр – исходное изображение,  второй – кортеж с требуемым разрешением для нового изображения, третий – алгоритм, который будет использоваться для масштабирования.

Вырезаем нужный фрагмент изображения

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

# вырежем участок изображения используя срезы
# мы же используем NumPy
cropped = image[30:130, 150:300]
cv2.imshow("Cropped image", cropped)
cv2.waitKey(0)

Что же мы получили? Ответ:

Участок с красной таблеткой из "Матрицы"

Участок с красной таблеткой из “Матрицы”

Данный код показывает преимущества работы с изображениями в стиле NumPy: мы просто используем срезы. В такой нотации мы вырезаем изображение с 30 по 130 пиксель по высоте и со 150 по 300 пиксель по ширине. Заметьте что высота идет первая – как мы говорили выше, первой идет строки, вторыми идут столбцы.

Поворот изображения на OpenCV 3 Python

Теперь перейдем к сложным вещам – афинным преобразованиям. Начнем с простого поворота на 180 градусов, без смещения. Следующий код поставит Нео с ног на голову:

# получим размеры изображения для поворота
# и вычислим центр изображения
(h, w) = image.shape[:2]
center = (w / 2, h / 2)

# повернем изображение на 180 градусов
M = cv2.getRotationMatrix2D(center, 180, 1.0)
rotated = cv2.warpAffine(image, M, (w, h))
cv2.imshow("Rotated image", rotated)
cv2.waitKey(0)

Выполнив код мы получим Нео и Морфеуса вниз ногами – что мы и хотели:

Повернутое изображение из "Матрицы" на OpenCV

Повернутое изображение из “Матрицы” на OpenCV

Разберем код подробнее:

  • Строки 3-4: Мы получаем размеры изображения через атрибут shape и среза по первым двум показателям – высоте и ширине. Далее мы вычисляем середину картинки для передачи ее в матрицу вращения, мы же хотим чтобы изображение осталось в центре. Для этого просто делим числа на 2.
  • Строка 7: Считаем матрицу для преобразования. В данном случае мы воспользовались методом cv2.getRotationMatrix2D, который может использоваться как для поворота изображения, так и для изменения его размеров. Данный метод принимает три аргумента – первый это кортеж с точкой, относительно которой будет осуществлен поворот изображения и изменение размера. Второй аргумент – угол поворота, в градусах. И третий аргумент – коэффициент увеличения, который может быть и меньше 1. Метод возвращает матрицу поворота, которая может использоваться в необходимых случаях.
  • Строка 8: Поворачиваем изображение. Используем метод cv2.warpAffine, который принимает три параметра – исходное изображения, матрицу преобразования, в данном случае матрицу поворота, и кортеж с размерами выходного изображения. Данный метод возвращает преобразованную картинку.
  • Строки 9-10: Показываем полученное изображение.

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

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

#отразим изображение по горизонтали
flip_image = cv2.flip(image,1)
cv2.imshow("Flip image", flip_image)
cv2.waitKey(0)

Выполнив данный код мы получим Морфеуса в зеркале:

Отражение кадра OpenCV

Отражение кадра OpenCV

В данном коде мы воспользовались методом cv2.flip, данный метод принимает два параметра – исходное изображение и ось для отражения. В качестве осей может быть следующие числа: 0 – по вертикали, 1 – по горизонтали, (-1) – по вертикали и по горизонтали.

Сохраняем изображение на локальный диск с OpenCV и Python

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

# запишем изображение на диск в формате png
cv2.imwrite("flip.png", flip_image)

Как мы видим, исполнение этого кода создает файл:

Сохраняем файл OpenCV

Сохраняем файл OpenCV

Как мы можем видеть, мы сохранили файл в формат PNG, при том что исходный файл был в формате JPG. Мы сделали это командой cv2.imwrite, которая принимает два аргумента, первый – путь файла, который будет создан, второй – изображение. Все операции по преобразованию формата OpenCV заботливо взял на себя.

Итог

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

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


7 Comments

вапрапр · 21/08/2020 at 23:01

где должна лежать эта картинка, чтобы она считалась, я уже сейчас застрелюсь

    Аноним · 14/09/2020 at 07:37

    Чтобы было проще, укажите явную ссылку на файл например: “C:\Users\UserName\Desktop\Works\image.jpg”

    Это один из способов. Не самый лучший, но рабочий.

max · 15/05/2020 at 11:33

Спасибо! С этого и начнем!

Anonymous · 26/11/2019 at 09:38

cropped = image[30:230, 320:620]

Ms.M · 25/04/2019 at 08:38

cropped = image[30:130, 150:300]
Вырезается черный фон из исходной картинки.

Elena · 23/04/2019 at 07:32

Неверно вырезается картинка с Нео.

Nikolay · 16/01/2019 at 20:01

Ссылка, на упомянутую в начале статьи, инструкцию “установка OpenCV 3 на Raspberry Pi 3 Jessie” не рабочая. Не могли бы Вы её поправить?

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.