Článek je překladem anglického originálu od Onuralpa Sezera. Oproti originálu je doplněno několik informací a vyjasněno pár nepřesností.

Vítejte zpátky u seriálu o OpenCV, ve kterém si ukazujeme, jak můžeme OpenCV využívat na Fedoře. V minulém díle jsme si ukázali naprosté základy: načítání obrázků, mapování barev a rozdíly mezi RGB a BGR. Kromě toho jsme se také naučili rozdělovat a spojovat barevné kanály a konvertovat obrázky mezi různými barevnými prostory. Ve druhém díle si ukážeme základní manipulaci s obrázky a jak provést transformace obrázků. Konkrétně si ukážeme:

  • Přístup k jednotlivým pixelům
  • Modifikaci pixelů v dané oblasti
  • Ořez
  • Změnu velikosti
  • Otáčení

Přístup k jednotlivým pixelům

import cv2
import numpy as np
import matplotlib.pyplot as plt

# Precteme obrazek jako sedotonovy
img = cv2.imread(cv2.samples.findFile("gradient.png"),0)
# Nastavime mapovani na sedoton pro spravne renderovani
plt.imshow(img, cmap='gray')
# Vytiskneme pixely jako 2D numpy array
print(img)
# Ukazeme si obrazek pomoci Matplotlibu
plt.show()

Jak jsme si řekli, obrázek je uložený jako numpy matice, takže pro přístup k individuálním pixelům použijeme klasickou notaci, jako bychom chtěli přistupovat k prvku matice: matice[r,c], kde r je číslo řádku (z anglického "row") a c je číslo sloupce (anglicky "column"), obé indexováno standardně od nuly. Pixel se souřadnicemi [0,0] je přitom vlevo nahoře a osy rostou dolů, resp. doprava (jako při zobrazování pixelů na orbazovce). Příkazy níže tedy vytisknou pixely z levého horního a pravého horního rohu.

# Vytiskni prvni pixel (= pixel v levem hornim rohu)
print(img[0,0])
# Vytiskni pixel v pravem hornim rohu
print(img[0,299])

Modifikace pixelů v dané oblasti

Pixely můžete modifikovat například tak, že  daným pixelům přímo změníme hodnotu. Pokud máme pixelů více, je dobré používat např. řez seznamem.

gr_img = img.copy()

# Pomaly zpusob: upravuj pixely jeden po druhem...
#gr_img[20,20] = 200
#gr_img[20,21] = 200
#gr_img[20,22] = 200
#gr_img[20,23] = 200
#gr_img[20,24] = 200
# ...

# Rychly zpusob: uprav vsechny pixely v oblasti se souradnicemi 20-80
gr_img[20:80,20:80] = 200

plt.imshow(gr_img, cmap='gray')
print(gr_img)
plt.show()

Ořezávání obrázků

Pokud chceme obrázek oříznout, jednoduše vybereme oblast pixelů, kterou potřebujeme:


import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread(cv.samples.findFile("starry_night.jpg"),cv.IMREAD_COLOR)
img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)
fig, (ax1, ax2) = plt.subplots(1,2)
ax1.imshow(img_rgb)
ax1.set_title('Před ořezem')
ax2.imshow(img_rgb[200:400, 300:600])
ax2.set_title('Po ořezu')
plt.show()

Změna velikosti obrázků

Syntaxe: dst = cv.resize( src, dsize[, dst[, fx[, fy[, interpolation]]]] )

Funkce resize() změní velikost obrázku src na rozměry dsize. Velikost přitom může být odvozena nejen z dsize, ale také z nepovinných parametrů fx a fy.

Povinné argumenty:

  • src: vstupní obrázek
  • dsize: výstupní velikost (může být i None, pokud použijeme fx a fy)

Nepovinné argumenty:

  • fx: Poměr pro horizontální osu. pokud je 0 (nebo není zadaný vůbec), vypočítá se poměr jako dsize.width/src.cols
  • fy: Poměr pro vertikální osu. Pokud je 0 nebo nezadán, vypočítá se jako dsize.height/src.rows
import cv2 as cv
import matplotlib.pyplot as plt

img = cv.imread(cv.samples.findFile("starry_night.jpg"), cv.IMREAD_COLOR)
img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)

plt.figure(figsize=[18, 5])
plt.subplot(1, 3, 1)  # row 1, column 3, count 1

cropped_region = img_rgb[200:400, 300:600]
resized_img_5x = cv.resize(cropped_region, None, fx=5, fy=5)
plt.imshow(resized_img_5x)
plt.title("Zvětšení oříznutého obrázku 5x")

width = 200
height = 300
dimension = (width, height)
resized_img = cv.resize(img_rgb, dsize=dimension, interpolation=cv.INTER_AREA)

plt.subplot(1, 3, 2)
plt.imshow(resized_img)
plt.title("Změna rozměrů na vlastní hodnotu")

desired_width = 500
aspect_ratio = desired_width / img_rgb.shape[1]
desired_height = int(img_rgb.shape[0] * aspect_ratio)
dim = (desired_width, desired_height)
resized_cropped_region = cv.resize(img_rgb, dsize=dim, interpolation=cv.INTER_AREA)

plt.subplot(1, 3, 3)
plt.imshow(resized_cropped_region)
plt.title("Vlastní velikost jedné strany, zachování poměrů")
plt.show()

Otáčení obrázků

Syntaxe: dst = cv.flip( src, flipCode )

Funkce flip() otočí obrázek src podle hodnoty flipCode, která může nabývat tří hodnot:

  • 0: otáčí obrázek kolem osy x
  • 1: otáčí obrázek podle osy y
  • -1: otáčí obrázek podle obou os
import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread(cv.samples.findFile("starry_night.jpg"),cv.IMREAD_COLOR)
img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)

img_rgb_flipped_horz = cv.flip(img_rgb, 1)
img_rgb_flipped_vert = cv.flip(img_rgb, 0)
img_rgb_flipped_both = cv.flip(img_rgb, -1)

plt.figure(figsize=[18,5])
plt.subplot(141);plt.imshow(img_rgb_flipped_horz);plt.title("Horizontální otočení");
plt.subplot(142);plt.imshow(img_rgb_flipped_vert);plt.title("Vertikální otočení");
plt.subplot(143);plt.imshow(img_rgb_flipped_both);plt.title("Otočení podél obou os");
plt.subplot(144);plt.imshow(img_rgb);plt.title("Originál");
plt.show()

A  to je pro tento díl vše!