OpenCV — быстрый старт: начало работы с изображениями

от автора

Перевожу родной OpenCV-шный туториал. И он хорош! (Сложно сказать, чем не понравились те, что есть.)
Изначально туториал в виде ноутбука, поэтому что-то я убрал. А что-то добавил. В общем, это помесь перевода с пересказом.

Вступление

Эта записнушка поможет с первыми шагами в изучении обработки изображений и машинном зрении через OpenCV. Несколько простых примеров объяснят важные вещи! Рассмотрим:

  • Как открыть изображение

  • Проверить его атрибуты, вроде формы или типа данных в нём

  • Матричное представление картинки в Numpy

  • Цветные картинки и работу с каналами изображения

  • Вывод изображения через matplotlib

  • Сохранение изображений

Импортируем нужные библиотеки

import cv2  # собственно OpenCV import numpy as np  # для работы с математикой import matplotlib.pyplot as plt  # для вывода картинки

Открываем изображения в OpenCV

Картинкой пойдёт крошечная доска в шашечку, 18×18 пикселей:

"checkerboard_18x18.png"
«checkerboard_18x18.png»

OpenCV позволяет работать с разными форматами: JPG, PNG, и так далее. Можно загружать цветные и чб-картинки, изображения с альфа-каналом. Для загрузки воспользуйтесь функцией cv2.imread().

cv2.imread() — синтаксис и аргументы

retval = cv2.imread( filename[, flags] )

retval: если картинка не загрузилась, в retval запишется None. Такое бывает при ошибке в имени/пути, или если изображение битое.

В функцию передаётся один обязательный аргумент и один необязательный флаг:

  1. filename: Может быть как относительным, так и абсолютным путём. Это обязательный аргумент.

  2. Flags: Флаги нужны для чтения изображения в определенном формате (например, в оттенках серого/цветном/с альфа-каналом). Необязательный аргумент! Значение по умолчанию cv2.IMREAD_COLOR или 1: этот флаг загрузит изображение как цветное.

Перед примерами посмотрим на пару флагов:

  1. cv2.IMREAD_GRAYSCALE или 0: Загружаем картинку как чёрно-белую

  2. cv2.IMREAD_COLOR или 1: Флаг по умолчанию, загружает картинку как цветную, без альфа-канала.

  3. cv2.IMREAD_UNCHANGED или -1: Загружает картинку в том виде, в котором она есть, включая альфу.

Флагов, конечно, больше.

Подробнее про imread(): ссылка на офф. документацию
Подробнее про флаги: ссылка на офф. документацию

Теперь посмотрим, что внутри шашечек:

# Читаем изображение как чёрно-белое cb_img = cv2.imread("checkerboard_18x18.png",0)  # Печатаем что прочитали. Каждый пиксель есть элемент двумерного массива numpy. # Значение пикселей восьмибитное: [0,255] print(cb_img)
чувствуется сходство
чувствуется сходство

Посмотрим атрибуты изображения

# вывод размера изображения (то есть, массива Numpy) print("Image size is ", cb_img.shape)  # тип данных в изображении (то есть, в массиве Numpy) print("Data type of image is ", cb_img.dtype)

В ответ получим:

>>>Image size is  (18, 18) >>>Data type of image is  uint8
Что за uint8?

8-bit unsigned integer arrays!
Uint8 — стандартный способ отображения изображений, где пиксель описывается диапазоном от 0 до 255. Если это изображение в градациях серого, пиксель со значением 0 является черным, а пиксель со значением 255 — белым.
Есть и другие форматы, конечно.

В общем, работаeт всё, что работает с ndarray: .ndim, .itemsize, .fill()

А теперь выведем картинку через matplotlib

Двумя командами:

# рисуем шашечки plt.imshow(cb_img)  # выводим шашечки plt.show()

Удивляемся:

шта?
шта?

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

# Поставим настройку color map plt.imshow(cb_img, cmap='gray')
так-то лучше!
так-то лучше!

Другой пример

Расплывчатые шашечки! Такие же, как в прошлый раз, но теперь с нечёткими гранями:

"checkerboard_fuzzy_18x18.jpg"
«checkerboard_fuzzy_18x18.jpg»
# Читаем картинку как чб cb_img_fuzzy = cv2.imread("checkerboard_fuzzy_18x18.jpg",0)  # Печатаем массив print(cb_img_fuzzy)  # Показываем картинку plt.imshow(cb_img_fuzzy,cmap='gray') plt.show()

Переходим к цвету

До этого момента мы говорили про чёрно-белые изображения, а теперь поговорим про цветные.

Подопытным кроликом будет лого колы:

"coca-cola-logo.png"
«coca-cola-logo.png»

Загружаем, проверяем размер и тип данных:

coke_img = cv2.imread("coca-cola-logo.png",1)  print("Image size is ", coke_img.shape)  print("Data type of image is ", coke_img.dtype)

В ответ получим:

>>>Image size is  (700, 700, 3) >>>Data type of image is  uint8

Размер картинки поменялся, потому как чб-изображение состоит из одного канала — от чёрного до белого, а цветное — из нескольких, например, трёх: RGB.

Выведем на экран уже известными манипуляциями:

plt.imshow(coke_img) plt.show()
Конфуз, однако.
Конфуз, однако.

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

#          ниже numpy-специфичная конструкция: #    (:) — взять каждый элемент по порядку, # (::-1) — взять каждый элемент, но в обратном порядке. coke_img_channels_reversed = coke_img[:, :, ::-1]  plt.imshow(coke_img_channels_reversed)
Так уже пококаколистей.
Так уже пококаколистей.

Разделение и объединение каналов

Две функции:

cv2.split()  —  разделит многоканальный массив на несколько одноканальных.
cv2.merge()  —  объединит массивы в один многоканальный. Массивы должны быть одинакового размера.

Проверим их на озере. В смысле, озером.

"New_Zealand_Lake.jpg"
«New_Zealand_Lake.jpg»
# Разбиваем картинку на каналы: B,G,R img_NZ_bgr = cv2.imread("New_Zealand_Lake.jpg",cv2.IMREAD_COLOR) b,g,r = cv2.split(img_NZ_bgr)  # Отрисовываем их plt.figure(figsize=[20,5]) plt.subplot(141);plt.imshow(r,cmap='gray');plt.title("Red Channel") plt.subplot(142);plt.imshow(g,cmap='gray');plt.title("Green Channel") plt.subplot(143);plt.imshow(b,cmap='gray');plt.title("Blue Channel")  # Собираем обратно в BGR imgMerged = cv2.merge((b,g,r)) # Выводим, что получилось plt.subplot(144);plt.imshow(imgMerged[:,:,::-1]);plt.title("Merged Output") plt.show()
точка с запятой в коде…

…не поощряется, но допускается. Помогает писать код в одну строку, а иногда это удобно!

Перевод в иные цветовые пространства

cv2.cvtColor()  —  преобразует изображение из одного цветового пространства в другое. В случае преобразования в RGB и из него порядок каналов надо указать явно: RGB или BGR. Формат цвета по умолчанию в OpenCV часто называют RGB, но на самом деле это BGR. Первый байт в стандартном 24-битном цветном изображении будет 8-битным синим компонентом, второй байт будет зеленым, а третий байт будет красным. Четвертый, пятый и шестой байты будут, соответственно, вторым пикселем  —  синий, зеленый, красный, и так до конца картинки.

Преобразование BGR в RGB

img_NZ_rgb = cv2.cvtColor(img_NZ_bgr, cv2.COLOR_BGR2RGB) plt.imshow(img_NZ_rgb) plt.show()

Преобразование в HSV

HSV  —  Hue, Saturation, Value — тон, насыщенность, значение.

img_hsv = cv2.cvtColor(img_NZ_bgr, cv2.COLOR_BGR2HSV) # Разобъём картинку на H,S,V каналы h,s,v = cv2.split(img_hsv)  # Нарисуем и покажем их plt.figure(figsize=[20,5]) plt.subplot(141);plt.imshow(h,cmap='gray');plt.title("H Channel") plt.subplot(142);plt.imshow(s,cmap='gray');plt.title("S Channel") plt.subplot(143);plt.imshow(v,cmap='gray');plt.title("V Channel") plt.subplot(144);plt.imshow(img_NZ_rgb);plt.title("Original")  plt.show()
Их и правда подрастянуло: кривой скрин
Их и правда подрастянуло: кривой скрин

Модификация отдельного канала

Хочется синий посиней? Есть решение!

img_NZ_bgr = cv2.imread("New_Zealand_Lake.jpg",cv2.IMREAD_COLOR) b,g,r = cv2.split(img_NZ_bgr)  b = b+50  # осиняем  plt.figure(figsize=[20,5]) plt.subplot(141);plt.imshow(r,cmap='gray');plt.title("Red Channel") plt.subplot(142);plt.imshow(g,cmap='gray');plt.title("Green Channel") plt.subplot(143);plt.imshow(b,cmap='gray');plt.title("Blue Channel")  imgMerged = cv2.merge((r,g,b))  # в этот раз соберём сразу RGB plt.subplot(144);plt.imshow(imgMerged);plt.title("Merged Output")  plt.show()
Чутка борщнул
Чутка борщнул

Сохранение изображений

Почти cv2.imread, только cv2.imwrite. Первым аргументом передаём путь и имя, вторым  —  изображение. Оба два обязательны. Расширение OpenCV подберёт, отталкиваясь от указанного в имени. Ещё можно докинуть параметров, и, например, указать качество JPG.

cv2.imwrite( filename, img[, params] )

Подробнее про imwrite(): ссылка на оф. документацию
Подробнее про параметры: ссылка на офф. документацию

Вот и всё! Первый маленький шажок к человеку-фотошопу пройден! До встречи в следующих сериях.


ссылка на оригинал статьи https://habr.com/ru/post/678260/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *