Судя по количеству закладок на первой части, работа моя — не зряшная.
В прошлый раз разбирали скучное открывание-закрывание картинки, в этот раз засунем в неё руки поглубже:
Доступ к пикселям и работа с ними.
Масштабирование картинки.
Обрезка.
Отражение.
import cv2 import numpy as np import matplotlib.pyplot as plt from PIL import Image
Первой картинкой пойдут уже знакомые шашечки:

Доступ к отдельным пикселям
Изображение в 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)

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

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")

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