OpenCV в Python: Часть 1 — Работа с изображениями и видео

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Перевод материала подготовлен в рамках курса "Python Developer. Basic".


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

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

Не будем терять времени, начнем!

Начало работы с OpenCV

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

pip install opencv-python

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

Для начала давайте импортируем необходимые библиотеки.

import cv2
import argparse

Модуль cv2 – это и есть OpenCV. Его мы будем использовать для анализа изображений и видео. Модуль argparse будет полезен при работе с аргументами, передаваемыми через терминал. Если вам неудобно работать с командой строкой, можете почитать это руководство (https://www.pyimagesearch.com/2018/03/12/python-argparse-command-line-arguments/), в котором все очень хорошо объясняется.

Работать мы будем с этим изображением.

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

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

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="path to input image")
args = vars(ap.parse_args())

После создания экземпляра argparse, добавим аргумент, который, по сути, сообщает, что изображение передается, как аргумент, и его нужно распарсить. Затем обработанный аргумент передается функции vars(), которая возвращает атрибут dict указанного объекта.

С помощью метода imread из cv2, мы положим изображение в переменную image.

image = cv2.imread(args["image"], cv2.IMREAD_GRAYSCALE)

Первый аргумент, передаваемый функции – это args[“image”], обработанный аргумент, содержащий путь к изображению. Поскольку мы сохранили изображение в той же папке, просто передадим имя файла изображения. 

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

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

cv2.imshow("Image", image)
cv2.waitKey(0)

cv2.waitKey(0) будет ждать, пока пользователь не нажмет любую клавишу, после чего окно с изображением закроется. 

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

(h, w) = image.shape[:2]

# display image properties
print("width: {} pixels".format(w))
print("height: {} pixels".format(h))

OpenCV позволяет сохранить этот файл и записать его на диск. Что интересно, OpenCV также под капотом обрабатывает преобразование типов, то есть вы можете сохранить изначально .jpeg файл в формате .png.

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

cv2.imwrite("folder/newimage.png", image)

А вот и полный код: 

import cv2
import argparse

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="path to input image")
args = vars(ap.parse_args())

image = cv2.imread(args["image"], cv2.IMREAD_GRAYSCALE)

cv2.imshow("Image", image)
cv2.waitKey(0)

(h, w) = image.shape[:2]

# display image properties
print("width: {} pixels".format(w))
print("height: {} pixels".format(h))

cv2.imwrite("photos/newimage.png", image)

Команда для выполнения файла:

python app.py --image photo_one.jpeg

Примечание: Я назвал файл с программой app.py, а файл с изображением photo_one.jpeg, не забудьте вставить свои названия.

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

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

Работа с видео в OpenCV

Теперь, когда мы закончили с изображениями, пришло время познакомиться с основами взаимодействия с веб-камерой или видеофайлами в OpenCV. Работа с видео мало чем отличается от работы с изображениями, поскольку видео состоит из кадров, которые по сути являются изображениями.

Для начала импортируем библиотеки.

import cv2
import numpy as np

Теперь создадим объект VideoCapture, чтобы, как следует из названия, «захватывать» видео.

cap = cv2.VideoCapture(0)

Число, которое мы передаем, означает источник. 0 – первая веб-камера в вашей системе, 1 – вторая и т.д.

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

Затем создадим цикл while, чтобы получать из источника кадр за кадром.

while True:
    ret, frame = cap.read()
    cv2.imshow('video feed', frame)

Функция cap.read() возвращает логическое значение (True/False) и кадр. Если кадр был считан верно, то возвращается True.

cv2.imshow() используется для отображения видео. Название видео будет первым аргументом.

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

if cv2.waitKey(1) & 0xFF == ord('q'):
    break

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

Функция waitKey(0) возвращает -1, когда ввод вообще не производится. Как только происходит событие, то есть нажимается кнопка, она возвращает 32-разрядное целое число.

В этом сценарии 0xFF – это 8-битный двоичный код 11111111, поскольку для представления символа «q». В результате вы получите целое число меньшее 255.

Следовательно, сравнивая целое число со значением ord(char), мы можем проверить событие нажатия клавиши и прервать цикл[1]. 

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

cap.release()
cv2.destroyAllWindows()

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

import cv2
import numpy as np

cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    cv2.imshow('video feed', frame)
    
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
        
cap.release()
cv2.destroyAllWindows()

После выполнения файла, вы увидите изображение с веб-камеры в окне под названием «video feed». Чтобы закрыть окно, нажмите «q».

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

В цикл while добавьте следующие инструкции: 

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('gray feed', gray)

После сохранения и выполнения файла вы получите два окна:

  1. Исходную версию.

  2. Версию в оттенках серого.

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

Также мы можем сохранить файл с помощью объекта VideoWriter. Перед этим нужно указать переменную fourcc (https://en.wikipedia.org/wiki/FourCC). FourCC – это 4-байтовый код, который используется для указания видеокодека. Полный список кодов можно посмотреть в кодеках FourCC (http://www.fourcc.org/codecs.php). 

fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))

Имя выходного файла будет первым аргументом. Затем нужно передать количество кадров в секунду (fps) и размер кадра. 

Чтобы сохранить видео, нужно записать каждый кадр в цикле while.

out.write(frame)
out.release()
cv2.destroyAllWindows()

Не забудьте в конце освободить экземпляр VideoWriter.

Полный код:

import cv2
import numpy as np

cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))

while True:
    ret, frame = cap.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    out.write(frame)

    cv2.imshow('video feed', frame)
    cv2.imshow('gray feed', gray)    

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
out.release()
cv2.destroyAllWindows()

После выполнения этого кода вы заметите, что видео с именем «output.avi» будет присутствовать в вашем главном каталоге. Вот видео, которое мы только что записали и сохранили на диск.

Итоги

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

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

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

Код на GitHub

Код – Часть 1 (https://github.com/sthitaprajna-mishra/opencv_in_python/tree/main/Part%201)

Сноски

  1. Getting Started with Videos — OpenCV-Python Tutorials 1 documentation (opencv-python-tutroals.readthedocs.io)


Узнать подробнее о курсе

"Python Developer. Basic"

Источник: https://habr.com/ru/company/otus/blog/558426/


Интересные статьи

Интересные статьи

Пост №2 для начинающих посвящен описательным статистикам, группированию данных и нормальному распределению. Все эти сведения заложат основу для дальнейшего анализа электо...
В предыдущей статье были тезисно расписаны основные идеи правильного масштабирования продукт-менеджмента в компаниях энтерпрайз уровня. Настало время рассмотреть каждую и...
О чём мы вспоминаем в первую очередь, когда слышим про распознавание образов? Сложные нейронные сети, мощные видеокарты, объёмные наборы данных. Всего этого не будет в мо...
В нашем блоге мы уже не один раз рассказывали о переезде в Нидерланды (раз, два). Разработчики, которые оказались в Амстердаме в один голос говорят о том, что с точки зрения технолог...
Сентябрь у многих уже ассоциируется с окончанием сезона отпусков, но у большинства — с учёбой. К началу нового учебного года предлагаем вам подборку видео наших образовательных проектов, выложе...