Найти в Дзене

2. Библиотека OpenCV

Оглавление

OpenCV (Open Source Computer Vision Library) — это библиотека с открытым исходным кодом для работы с компьютерным зрением. Изначально она была написана на C++, но адаптирована для использования на Python, С, Java и MATLAB.

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

  • Core Functionality (основная функциональность) — определяет основные структуры данных и функции библиотеки, которые используются в других модулях.
  • Image Processing (обработка изображений) — позволяет работать со статичными изображениями: простыми картинками в форматах PNG, JPG и других.
  • Video Analysis (анализ видео) — используется для отслеживания движений объектов и работы с фоном.
  • Camera Calibration and 3D Reconstruction (калибровка камеры и 3D-реконструкция) — работает с геометрией объектов, позволяя создавать их 3D-модели на основе нескольких изображений или видео.
  • 2D Features Framework (фреймворк двумерных особенностей) — определяет фрагменты изображения, которые отличаются от других, запоминая их контуры, и может находить похожие среди них.
  • Object Detection (обнаружение объектов) — находит объекты, например лица, автомобили, птиц и другое.
  • High-level GUI (высокоуровневый графический интерфейс) — позволяет рисовать графические интерфейсы для выполнения простых операций.
  • Video I/O (ввод и вывод видео) — позволяет считывать и обрабатывать видеофайлы.

Установка OpenCV

Скачать библиотеку можно с помощью инструментов вашей IDE или с помощью командной строки:

можно импортировать модуль и приступать к работе:

import cv2

Библиотека работает с изображениями как с NumPy-массивами. Если изображение в оттенках серого, то массив этот двумерный. Каждый пиксель в изображении представлен в виде числа 0 до 255, где 0 — чёрный, 255 — белый, а всё остальное — оттенки серого между ними.

Каждая пиксельная строка объединена в одномерный массив. Например, [255, 255, 77, 77, 77, 255, 255]. Это строка из семи пикселей: двух белых, трёх серых и ещё двух белых.

Каждая такая пиксельная строка объединена в массив второго уровня. Например:

-2

В итоге получается вот такое изображение, только в 100 раз меньше:

-3

Если изображение цветное, то потребуется трёхмерный массив. Цвет каждого пикселя описывает не одно, а сразу три числа от 0 до 255 — в соответствии с моделью RGB. Только красный и синий цвет переставлены местами, так что первое число отвечает за синий цвет, второе — за зелёный, третье — за красный: получается BGR.

Вот примеры пикселей разного цвета на языке OpenCV:

  • [0, 0, 0] — чёрный.
  • [255, 255, 255] — белый.
  • [255, 0, 0] — синий.
  • [0, 255, 0] — зелёный.
  • [0, 0, 255] — красный.
  • [0, 255, 255] — жёлтый.
  • [203, 192, 255] — розовый.

Таблицу распространённых цветов в RGB можно посмотреть здесь. Только помните, что в OpenCV первый и третий цвета переставлены местами.

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

Вот так в OpenCV будет выглядеть массив для изображения из девяти цветных пикселей:

-4

само изображение в увеличении такое:

-5

Чтение, режимы отображения и запись

Например, вот такое изображение:

-6

Прочитаем изображение и откроем его в отдельном окне:

-7
  • cv2.imread — «читает» изображение и возвращает NumPy-массив, с которым библиотека может работать. В качестве аргумента получает полный или относительный путь к изображению.
  • cv2.imshow — открывает изображение в отдельном окне операционной системы. Первым аргументом получает название окна, вторым — NumPy-массив, в нашем случае он хранится в переменной image.
  • cv2.waitKey — если не указать эту функцию, то открытое окно тут же закроется. В качестве аргумента получает кнопку, которую нужно нажать, чтобы закрыть окно. Если указать 0, то окно закроется при нажатии любой кнопки.

Можно передать функции cv2.imread необязательный второй аргумент и выбрать режим отображения:

  • cv2.IMREAD_COLOR (по умолчанию) — цветное отображение в формате RGB.
  • cv2.IMREAD_GRAYSCALE — отображение в оттенках серого.

Таким образом, функцию cv2.imread можно использовать, чтобы обесцветить цветное изображение:

-8

получится:

-9

чтобы сохранить новое изображение в отдельный файл нужно использовать cv2.imwrite :

-10

Первым аргументом функция принимает название нового файла с картинкой, вторым — NumPy-массив с данными изображения.

Изменение цвета пикселей

Для начала получим доступ к пикселю. Для этого обратимся к нему по координатам. Сначала указываем координаты ширины, потом — высоты. Например:

-11

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

image[0, 0] = [255, 0, 0]

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

  • image.shape[0] — высота изображения в пикселях.
  • image.shape[1] — ширина изображения в пикселях.

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

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

-12

получается:

-13

Чтобы изменить размер изображения, используйте функцию cv2.resize. Уменьшим нашу картинку в два раза:

-14
  • image — NumPy-массив изображения, размер которого мы изменяем.
  • (399, 368) — ширина и высота нового изображения.
  • cv2.INTER_AREA — метод интерполяции, то есть алгоритм, по которому OpenVC выбирает, в какие цвета красить пиксели.

Есть несколько методов интерполяции, но в большинстве случаев достаточно двух из них:

  • cv2.INTER_LINEAR — для увеличения изображения. Используется по умолчанию, если не указано иное.
  • cv2.INTER_AREA — для уменьшения картинки.

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

-15

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

-16
-17

Чтобы повернуть картинку, используйте сразу две функции:

-18

Функция cv2.getRotationMatrix2D задаёт матрицу, по которой будет повёрнуто изображение. Она получает следующие аргументы:

  • (399, 368) — координаты точки, вокруг которой происходит поворот.
  • 60 — угол поворота в градусах.
  • 0.8 — коэффициент масштабирования. В нашем случае мы уменьшаем изображение, чтобы части логотипа не вышли за край.

Функция cv2.warpAffine непосредственно поворачивает изображение. Она получает следующие аргументы:

  • image — само изображение.
  • matrix — матрица, созданная функцией cv2.getRotationMatrix2D.
  • (image.shape[1], image.shape[0]) — размеры итогового изображения. В нашем случае мы оставляем те же, что были.
-19

Отображение координат точки

import cv2

# функция реакции на нажатие левой или правой кнопки мыши def click_event(event, x, y, flags, params):
# если нажата левая кнопка мыши if event == cv2.EVENT_LBUTTONDOWN:
# выводим координаты и BGR-код точки в терминал print(f'Координаты точки: {x}, {y}')
b = img[y, x, 0]
g = img[y, x, 1]
r = img[y, x, 2]
print(f'BGR-код точки: {b}, {g}, {r}\n')

# рисуем координаты точки на изображении font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, f'{x}, {y}', (x, y),
font, 1, (0, 0, 0), 2)
cv2.imshow('image', img)

# если нажата правая кнопка мыши if event == cv2.EVENT_RBUTTONDOWN:
# узнаём BGR-код точки и сохраняем в переменные b = img[y, x, 0]
g = img[y, x, 1]
r = img[y, x, 2]

# выводим координаты и BGR-код точки в терминал print(f'Координаты точки: {x}, {y}')
print(f'BGR-код точки: {b}, {g}, {r}\n')

# рисуем BGR-код точки на изображении font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, f'{b}, {g}, {r}', (x, y),
font, 1, (0, 0, 0), 2)
cv2.imshow('image', img)


# основной сценарий if __name__ == "__main__":
img = cv2.imread('logo.jpg', 1)
cv2.imshow('image', img)
# устанавливаем реакцию на действия мыши и вызываем функцию click_event cv2.setMouseCallback('image', click_event)
cv2.waitKey(0)

В итоге:

-20