Skip navigation

Zajszűrés konvolúcióval

Bemeneti adat

A továbbiakban egycsatornás képeket feltételezünk. Többcsatornás kép esetén csatornánként külön hajtódnak végre a műveletek.

Átlagoló szűrés konvolúcióval

A legáltalánosabb megoldási lehetőség a konvolúció használata, ami a képpontok egy környezetében elvégzett súlyozott átlag számítását jelenti. A súlyokat egy kxk méretű mátrixban adjuk meg. A mátrix rendszerint páratlan számú sorból és oszlopból áll, hogy a középső elem egyértelműen meghatározható legyen. Ez a középső elem illeszkedik az éppen vizsgált képpontra. Nagyobb k értékek esetén erősebb a simítás hatása, mert nagyobb területen számolódik az átlag, és a végrehajtási idő is jelentősen megnő!

Simítás esetén elvárás, hogy kép összfényessége ne változzon. Ezt úgy érhetjük el, ha a maszkelemek összege 1. Tört számok helyett a könnyebb átláthatóság miatt sokszor egész számokkal adjuk meg a maszk elemeit, a szükséges normalizáló osztás kiemeljük a mátrix elé. Ez csak jelölésmódbeli különbség.

A konvolúciós mátrixot Numpy tömbként definiálhatjuk, például a sima átlagoló szűrő esetén:

kernel = np.array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])

kernel = kernel / 9.0

Gauss-simítás esetén a súlyok a középponttól távolodva csökkennek. Itt a szórás paraméter befolyásolja a simítás erősségét, a maszk mérete pedig a Gauss-függvény reprezentációjának pontosságát és területi kiterjedését.

Konvolúciós maszkok 5x5 és 15x15 méretű Gauss simítás esetén 2.0 értékű szórással (jól látható, hogy ilyen maszkokat nem manuálisan begépelve érdemes megadni, hanem függvények használatával előállítani):

\frac{1}{604} \; \cdot \; \begin{bmatrix} 1 & 8 & 13 & 8 & 1 \\ 8 & 36 & 60 & 36 & 8 \\ 13 & 60 & 100 & 60 & 13 \\ 8 & 36 & 60 & 36 & 8 \\ 1 & 8 & 13 & 8 & 1 \end{bmatrix}

Gauss blur 5x5 sigma 2.0

\frac{1}{1704} \; \cdot \; \begin{bmatrix} 1 & 3 & 4 & 7 & 9 & 11 & 12 & 13 & 12 & 11 & 9 & 7 & 4 & 3 & 1 \\ 3 & 5 & 8 & 11 & 15 & 19 & 22 & 23 & 22 & 19 & 15 & 11 & 8 & 5 & 3 \\ 4 & 8 & 12 & 18 & 24 & 30 & 34 & 36 & 34 & 30 & 24 & 18 & 12 & 8 & 4 \\ 7 & 11 & 18 & 27 & 36 & 44 & 49 & 52 & 49 & 44 & 36 & 27 & 18 & 11 & 7 \\ 9 & 15 & 24 & 36 & 47 & 58 & 66 & 69 & 66 & 58 & 47 & 36 & 24 & 15 & 9 \\ 11 & 19 & 30 & 44 & 58 & 72 & 81 & 84 & 81 & 72 & 58 & 44 & 30 & 19 & 11 \\ 12 & 22 & 34 & 49 & 66 & 81 & 92 & 96 & 92 & 81 & 66 & 49 & 34 & 22 & 12 \\ 13 & 23 & 36 & 52 & 69 & 84 & 96 & 100 & 96 & 84 & 69 & 52 & 36 & 23 & 13 \\ 12 & 22 & 34 & 49 & 66 & 81 & 92 & 96 & 92 & 81 & 66 & 49 & 34 & 22 & 12 \\ 11 & 19 & 30 & 44 & 58 & 72 & 81 & 84 & 81 & 72 & 58 & 44 & 30 & 19 & 11 \\ 9 & 15 & 24 & 36 & 47 & 58 & 66 & 69 & 66 & 58 & 47 & 36 & 24 & 15 & 9 \\ 7 & 11 & 18 & 27 & 36 & 44 & 49 & 52 & 49 & 44 & 36 & 27 & 18 & 11 & 7 \\ 4 & 8 & 12 & 18 & 24 & 30 & 34 & 36 & 34 & 30 & 24 & 18 & 12 & 8 & 4 \\ 3 & 5 & 8 & 11 & 15 & 19 & 22 & 23 & 22 & 19 & 15 & 11 & 8 & 5 & 3 \\ 1 & 3 & 4 & 7 & 9 & 11 & 12 & 13 & 12 & 11 & 9 & 7 & 4 & 3 & 1 \end{bmatrix}

Gauss blur 15x15 sigma 2.0

Konvolúció végrehajtása általunk megadott maszkkal

Konvolúciót a cv2.filter2D() függvénnyel végezhetünk. Első paramétere a szűrendő kép. A második az eredmény kép típusa. Ha -1 értéket adunk meg, akkor megegyezik a bemenet típusával. A harmadik paraméter a végrehajtandó konvolúciós mátrix. Teljes fejléc definíció:

dst = cv2.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])

dst Eredménykép
src Forráskép
ddepth

Eredménykép típusa.
-1: megegyezik src típusával.

Egyébként ha

  • src.depth == CV_8U, akkor ddepth lehet CV_16S, CV_32F, CV_64F
  • src.depth == CV_16U vagy CV_16S, akkor ddepth lehet CV_32F, CV_64F
  • src.depth == CV_32F, akkor ddepth lehet CV_32F, CV_64F
  • src.depth == CV_64F, akkor ddepth csak CV_64F lehet.

Vagyis az eredmény típusa nem lehet "pontatlanabb", mint a forrás.

kernel Egycsatornás 2D lebegőpontos mátrix, ami a konvolúciós maszkot definiálja.
anchor A maszk melyik pontját kell a képpontra igazítani.
Alapértelmezés: (-1, -1), ami a maszk közepét jelenti.
delta Opcionális érték, ami a súlyozott összeghez kerül hozzáadásra. Alapértéke 0.
borderType Extrapolációs módszer a kép határán. Alapértelmezés: BORDER_DEFAULT.

Használati példa

imnoisefilter = cv2.filter2D(imnoise, -1, kernel)

Példaprogram

  • 06_03_filter2d.py

Érdekesség

A konvolúciót számos további alacsonyszintű képfeldolgozó feladat megoldására fel tudjuk használni a konvolúciós maszk megfelelő választásával.

Próbáljuk ki az alábbi maszkok hatását! A reshape() segítségével egy mátrix alakját módíthatjuk. Jelen példákban egy 9 elemű sorvektorból 3x3 méretű mátrix alakba.

sharpen_kernel = np.array([0, -1, 0, -1, 5, -1, 0, -1, 0]).reshape((3, 3, 1))
emboss_kernel = np.array([-2, -1, 0, -1, 1, 1, 0, 1, 2]).reshape((3, 3, 1))

OpenCV szűrések

Az OpenCV a konkrét szűrési feladatra közvetlenül használható függvényeket is biztosít. Ezek előnye, hogy nem kell külön a konvolúciós maszkot definiálnunk, a megadott paraméterek szerint a függvények előállítják és végre is hajtják.

Átlagoló szűrés

Egyforma súlyokkal történő átlagoló szűrést a cv2.blur() függvénnyel végezhetünk. A második paramétere egy tuple objektum, ami a konvolúciós mátrix méretét adja. Teljes függvény fejléc:

dst = cv2.blur(src, ksize[, dst[, anchor[, borderType]]])

Az anchor és a borderType megegyezik a cv2.filter2D() függvénynél megismerttel.

Használati példa:

imnoiseblur5x5 = cv2.blur(imnoise, (5, 5))

Gauss-szűrés

A vizsgált képpontól távolodva egyre kisebb (Gauss-függvény szerinti) súlyt alkalmazhatunk a cv2.GaussianBlur() függvénnyel. A maszkméret mellett az X és Y irányú szórás értékeket adhatjuk meg.

dst = cv2.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])

Vigyázzunk arra, hogy a sigmaX paraméter után sorrendileg a dst következik, amit általában nem használunk fel, mert a függvény visszaadott értékét érdemes átvenni! Ha sigmaY értéket is meg akarunk adni, akkor a sigmaX után kell a None, vagy még jobb, ha egyértelműen megadjuk, melyik paraméter melyik értéket kapja, ahogyan a táblázat alatti használati példában láthatjuk is.

Ha mindkét szórás érték 0 értékű, akkor a ksize méretből számol az OpenCV. Az egyértelműség miatt célszerű a ksize és legalább a sigmaX egyértelmű megadása!

dst Eredménykép.
src Forráskép.
ksize Tuple objektum, ami a maszk méretét adja. Páratlan pozitív egész értékek adhatók meg, de lehetnek különbözőek.
sigmaX X-irányú szórás.
sigmaY Y-irányú szórás. Ha nem adjuk meg, akkor a sigmaX értékével számol.
borderType Extrapolációs módszer a kép határán. Alapértelmezés: BORDER_DEFAULT.

Használati példa:

imnoisegauss5x5 = cv2.GaussianBlur(imnoise, (5, 5), sigmaX=2.0, sigmaY=2.0)

Példaprogramok

  • 06_04_a_blur.py
  • 06_04_b_blur_tb.py

Élmegőrző simítás

Az átlagoló szűrők hátránya, hogy az éleket is homályosítják. Az OpenCV a bilaterális szűrőjével a simítás az élek mentén kevésbé kerül alkalmazásra. A műveletet részletesen nem tárgyaljuk. További információt az angol nyelvű dokumentációban, valamint a műveletet bemutató honlapon találhatunk.