OpenCV — быстрый старт: базовые операции с изображениями

от автора

Судя по количеству закладок на первой части, работа моя  —  не зряшная.
В прошлый раз разбирали скучное открывание-закрывание картинки, в этот раз засунем в неё руки поглубже:

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

  • Масштабирование картинки.

  • Обрезка.

  • Отражение.

import cv2 import numpy as np import matplotlib.pyplot as plt from PIL import Image

Первой картинкой пойдут уже знакомые шашечки:

"checkerboard_18x18.png"
«checkerboard_18x18.png»

Доступ к отдельным пикселям

Изображение в OpenCV — матрица numpy, а значит, для доступа к пикселю будем использовать нотацию матриц: [r, c]. Первое значение  — строка, второе  — колонка. Не забывайте о том, что индексация начинается с нуля!

Для доступа к самому первому пикселю обратимся к элементу матрицы (изображения, то бишь) с индексами 0 и 0:

# Читаем картинку как чб cb_img = cv2.imread("checkerboard_18x18.png",0) # Выводим массив, представляющий картинку print(cb_img) # Выводим значение самого первого пикселя (верх-лево) print(cb_img[0,0]) # Выводим значение первого пикселя слева от чёрной зоны print(cb_img[0,6])

С доступом разобрались, поиграем со значениями.

Изменение пикселей

Просто переназначаем пиксель:

cb_img[0,0] = 255

Что-то похожее мы сделали в прошлый раз с каналами.

Продублируем картинку, и накидаем в неё серых пикселей:

cb_img_copy = cb_img.copy()# копируем загруженное изображение cb_img_copy[2,2] = 200# пиксель в ячейке [2,2] будет равен 200 cb_img_copy[2,3] = 200# и так далее cb_img_copy[3,2] = 200 cb_img_copy[3,3] = 200  # То же самое другими словами: # cb_img_copy[2:3,2:3] = 200  plt.imshow(cb_img_copy, cmap='gray') plt.show() print(cb_img_copy)

Обрезка картинок

Можно воспринимать кроп как задачу «из пачки пикселей берём только эти несколько».
Загрузим новозеландскую лодку и потренируемся на ней:

"New_Zealand_Boat.jpg"
«New_Zealand_Boat.jpg»
img_NZ_bgr = cv2.imread("New_Zealand_Boat.jpg",cv2.IMREAD_COLOR) # или так: # img_NZ_bgr = cv2.imread("New_Zealand_Boat.jpg",1) # img_NZ_bgr = cv2.imread("New_Zealand_Boat.jpg")  img_NZ_rgb = img_NZ_bgr[:,:,::-1] # или так: # img_NZ_rgb = cv2.cvtColor(img_NZ_bgr, cv2.COLOR_BGR2RGB) # или разбить на каналы и пересобрать в правильном порядке :)  plt.imshow(img_NZ_rgb) plt.show()

Вырежем серединку:

# кропнутый регион = область загруженной картинки # c 200 по 400 строку (или Y, если хотите) # и 300 по 600 колонку (или X, если хотите) cropped_region = img_NZ_rgb[200:400, 300:600]  plt.imshow(cropped_region) plt.show()

Масштабирование изображений

Функция resize() отресайзит картинку в больший или меньший размер. А регулируется это всё аргументами src,dsize (обязательные),fx, fy (факультативные).

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

dst = resize( src, dsize[, dst[, fx[, fy[, interpolation]]]] )

dst — изображение на выходе. Размер картинки будет равен dsize (если он ненулевой), или посчитан через src.size(), fx, fy.
Тип данных будет тем же, что и в оригинальной картинке.

src — понятно, сама картинка, требующая вмешательства. Обязательный аргумент.
dsize — необходимый размер, обязательный аргумент.
fx — коэффициент масштаба горизонтальный.
fy
— коэффициент масштаба вертикальный.

Чуть подробнее о том, что тут происходит

В общем: в dsize кладётся кортеж с натуральными числами, две штуки: (500, 500). Это размер, в который картинка отмасштабируется.
Можно воспользоваться вместо этого коэффициентами масштаба, тогда вместо dsize надо впечатать None.
Коэффициенты масштаба — fx и fy — берут оригинальную картинку, и растягивают/стягивают её пропорционально.

dsize — имеет приоритет: конструкция resize(src, dsize=(100, 100),fx=20, fy=20) выдаст картинку 100×100 пикселей.

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

Первый вариант масштабирования: коэффициенты масштаба

Увеличим кропнутую лодку в два раза:

resized_cropped_region_2x = cv2.resize(cropped_region,None,fx=2, fy=2) plt.imshow(resized_cropped_region_2x) plt.show()

Второй вариант масштабирования: сразу укажем нужные размеры

desired_width = 100  # желаемая ширина desired_height = 200  # желаемая высота dim = (desired_width, desired_height)  # размер в итоге  # Масштабируем картинку resized_cropped_region = cv2.resize(cropped_region,                                     dsize = dim,                                     interpolation = cv2.INTER_AREA)  # Или так: # resized_cropped_region = cv2.resize(cropped_region, #                                   dsize = (100, 200), #                                   interpolation = cv2.INTER_AREA)  plt.imshow(resized_cropped_region) plt.show()

Масштабирование с сохранением пропорций

За основу возьмём вторую методу, но отталкиваться будем от желаемой ширины.
Немного несложной математики:

# Используем 'dsize'  desired_width = 100  # желаемая ширина  # соотношение сторон: ширина, делённая на ширину оригинала aspect_ratio = desired_width / cropped_region.shape[1]  # желаемая высота: высота, умноженная на соотношение сторон desired_height = int(cropped_region.shape[0] * aspect_ratio)  dim = (desired_width, desired_height)  # итоговые размеры  # Масштабируем картинку resized_cropped_region = cv2.resize(cropped_region, dsize=dim, interpolation=cv2.INTER_AREA) plt.imshow(resized_cropped_region) plt.show()

Сохранимся-с!

# Приводим картинку к RGB resized_cropped_region_2x = resized_cropped_region_2x[:,:,::-1]  # Сохраняем картинку cv2.imwrite("resized_cropped_region_2x.png", resized_cropped_region_2x)  # Посмотрим на сокранённую картинку (тут-то нам и пригодится подгруженный PIL) im = Image.open('resized_cropped_region_2x.png') im.show()

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

Происходит с помощью функции flip().

dst = cv.flip( src, flipCode )

src — понятно, сама картинка, требующая вмешательства. Обязательный аргумент.
flipCode — флаг, объясняющий функции, как конкретно мы хотим картинку отразить.

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

img_NZ_rgb_flipped_horz = cv2.flip(img_NZ_rgb, 1) img_NZ_rgb_flipped_vert = cv2.flip(img_NZ_rgb, 0) img_NZ_rgb_flipped_both = cv2.flip(img_NZ_rgb, -1)  plt.figure(figsize=[18,5]) plt.subplot(141);plt.imshow(img_NZ_rgb_flipped_horz);plt.title("Horizontal Flip"); plt.subplot(142);plt.imshow(img_NZ_rgb_flipped_vert);plt.title("Vertical Flip") plt.subplot(143);plt.imshow(img_NZ_rgb_flipped_both);plt.title("Both Flipped") plt.subplot(144);plt.imshow(img_NZ_rgb);plt.title("Original")

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


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