Lekce 3 - Práce s pixely a operace s obrázky v Pythonu
V předchozí lekci, Práce s videem v Pythonu a kreslení a psaní do obrázků, jsme si ukázali, jak načíst, přehrát a uložit video v různých formátech v knihovně OpenCV v Pythonu a také kreslení tvarů a textu do obrázků.
V dnešním Python tutoriálu si ukážeme, jak pracovat s pixely a provádět aritmetické operace s obrázky.
Práce s pixely
Z předchozích lekcí již víme, že video se skládá z jednotlivých snímku/obrázků, které se skládají z pixelů a ty jsou uspořádány v 2D listu.
Jako vždy budu v ukázkách používat obrázek níže:

Nejdříve si obrázek načteme:
import cv2 import numpy as np img = cv2.imread("letadlo.jpg")
Změna barvy pixelu
Vypíšeme si barvu pixelu, který se nachází na pozici
250x330
. V numpy se index u vícerozměrných polí rozděluje
pomocí čátky ,
:
print(img[250, 330])
Barvu pixelu zkusíme také změnit a obrázek znovu vykreslit:
print(img[250, 330]) img[250, 330] = [255,255,255] print(img[250, 330]) cv2.imshow("obrazek", img) cv2.waitKey() cv2.destroyAllWindows()
Ujistíme se, že se barva opravdu změnila.

Změna barvy oblasti v obrázku
Takto můžeme změnit barvu vybrané části obrázku a ne pouze jednomu
pixelu. Níže vybereme oblast od bodu [250:500]
do bodu
[330:600]
:
img[250:500, 330:600] = [255,255,255] cv2.imshow("obrazek", img) cv2.waitKey() cv2.destroyAllWindows()
Při indexování můžeme použít jednu z následujících hodnot:
img.size
- počet bodů v obrázku (u obrázku letadla =2980680
)img.shape
- rozměry obrázku a počet barevných složek (u obrázku letadla =(842, 1180, 3)
)- Pokud chceme znát datový typ obrázku, zjistíme ho pomocí
img.dtype
Nyní si zkusíme zkopírovat vybrané pixely a vložit je na libovolnou pozici:
img[200:300, 500:600] = img[400:500, 200:300]
Výsledek:

Aritmetické operace s obrázky
Abychom si mohli ukázat aritmetické operace s obrázky, potřebujeme druhý obrázek. Já použiji tento:

Nejprve zkusíme pole pixelů obrázků sečíst:
letadlo = cv2.imread("letadlo.jpg") kocka = cv2.imread("kocka.jpg") kocka = kocka[:letadlo.shape[0], :letadlo.shape[1]] img = letadlo + kocka cv2.imshow("obrazek", img) cv2.waitKey() cv2.destroyAllWindows()
Jelikož obrázek s kočkou je větší, musíme ho přizpůsobit velikosti
letadla pomocí
kocka = kocka[:letadlo.shape[0], :letadlo.shape[1]]
. Poté je
jednoduše sečteme pomocí img = letadlo + kocka
.

Tohle se nám úplně nevydařilo, jelikož jen tak 2 obrázky sečíst
nemůžeme. Obrázek je strašně světlý, protože při sčítaní pixelů,
např. hodnot [150, 200, 230] + [50, 80, 140]
nám vyjde
[200, 280, 370]
, což se ořízne na maximální hodnoty
[200, 255, 255]
.
Abychom tomuto předešli, obrázky do sebe prolneme funkcí
cv2.addWeighted(obrázek1, poměr/váha obrázku1, obrázek2, poměr/váha obrázku2, gamma)
:
img = cv2.addWeighted(letadlo, 0.4, kocka, 0.75, 0)
Výsledek je mnohem působivější:

Obrázek je ale stále poměrně světlý, proto nastavíme hodnotu gamma na
-100
:
img = cv2.addWeighted(letadlo, 0.4, kocka, 0.75, -100)
Výsledný obrázek vypadá mnohem lépe

Vložení obrázku do obrázku bez prolnutí
Na závěr si ukážeme pro nás poměrně náročnou operaci, kdy vložíme jeden obrázek do druhého bez prolnutí. Jako ukázku si vložíme logo ITnetworku do obrázku s letadlem. Logo je následující obrázek typu PNG:

Na letadlo jej vložíme tak, aby byla bílá barva průhledná. Uveďme si nejprve kompletní zdrojový kód, který si záhy popíšeme:
letadlo = cv2.imread("letadlo.jpg") itn = cv2.imread("itn.png") region = letadlo[ 0:itn.shape[0], 0:itn.shape[1] ] itn_seda = cv2.cvtColor(itn, cv2.COLOR_BGR2GRAY) ret, maska = cv2.threshold(itn_seda, 150, 255, cv2.THRESH_BINARY_INV) maska_inv = cv2.bitwise_not(maska) letadlo_bg = cv2.bitwise_and(region, region, mask = maska_inv) itn_bez_bg = cv2.bitwise_and(itn, itn, mask = maska) logo_celek = cv2.add(letadlo_bg, itn_bez_bg) letadlo[ 0:itn.shape[0], 0:itn.shape[1] ] = logo_celek
Nejdříve si definujeme region v obrázku letadlo, kam logo vložíme. My
jej vložíme do levého horního rohu, region tedy bude
region = letadlo[ 0:itn.shape[0], 0:itn.shape[1] ]
. Logo převedeme
z barevného na šedé pomocí
itn_seda = cv2.cvtColor(itn, cv2.COLOR_BGR2GRAY)
, abychom později
mohli oddělit pozadí. Vytvoříme masku, která nám oddělí bílé pozadí
jako
cv2.threshold(obrázek, práh, maximální hodnota, typ operace)
.
Tato funkce převede pixely buď na černé nebo bílé. Poté použijeme
bitovou operaci a vytvoříme tak další masku s opačnou hodnotou
maska_inv = cv2.bitwise_not(maska)
. Aplikujeme
maska_inv
na vybraný region z obrázku letadlo jako
letadlo_bg = cv2.bitwise_and(region, region, mask = maska_inv)
.
Poté aplikujeme maska
na logo pomocí bitové operace, tím se
zbavíme pozadí
itn_bez_bg = cv2.bitwise_and(itn, itn, mask = maska)
a nakonec logo
vložíme do obrázku jako
letadlo[ 0:itn.shape[0], 0:itn.shape[1] ] = logo_celek
.
Na bitové operace a thresholding se podíváme podrobněji v
následujících lekcích

Zdrojový kód najdete ke stažení v příloze článku.
V další lekci, Thresholding a analýza obrázků v Pythonu, se zaměříme na thresholding v knihovně OpenCV.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 43x (520.98 kB)
Aplikace je včetně zdrojových kódů v jazyce Python