Skip navigation

Elsőrendű parciális derivált közelítése

Operátorok elsőrendű parciális derivált közelítésére

Sobel operátor

X-irányú parciális derivált közelítése az alábbi konvolúciós maszkkal. X-irányú élekre érzékeny. Figyeljük meg, hogy a vizsgált képpont jobb oldali szomszédainak súlyozott összegéből vonjuk ki a bal oldaliak súlyozott összegét.

G_x= \left[ \begin{matrix} -1 & 0 & +1 \\ -2 & 0 & +2 \\ -1 & 0 & +1 \end{matrix} \right]

Y-irányú parciális derivált közelítése. Y-irányú élekre érzékeny. Itt a vizsgált képpont alsó és felső szomszédai játszanak szerepet.

G_y = \left[ \begin{matrix} +1 & +2 & +1 \\ 0 & 0 & 0 \\ -1 & -2 & -1 \end{matrix} \right]

Scharr operátor

Pontosabb közelítést adhat, mint a Sobel.

G_x= \left[ \begin{matrix} -3 & 0 & +3 \\ -10 & 0 & +10 \\ -3 & 0 & +3 \end{matrix} \right]

G_y = \left[ \begin{matrix} +3 & +10 & +3 \\ 0 & 0 & 0 \\ -3 & -10 & -3 \end{matrix} \right]

Frei-Chen operátor

Még pontosabb, de egész számok helyett lebegőpontos reprezentáció szükséges.

G_x= \left[ \begin{matrix} -1 & 0 & +1 \\ -\sqrt{2} & 0 & +\sqrt{2} \\ -1 & 0 & +1 \end{matrix} \right]

G_y = \left[ \begin{matrix} +1 & +\sqrt{2} & +1 \\ 0 & 0 & 0 \\ -1 & -\sqrt{2} & -1 \end{matrix} \right]

A szakirodalomban még számos további művelettel találkozhatunk (Roberts, Prewitt, stb.), valamint kidolgoztak más irányú (pl. 45 fokos) élekre érzékeny operátorokat is.

Parciális deriváltak felhasználása éldetektáláshoz

Lépések

Eredeti szürkeárnyalatos kép, erős élekkel. X-irányú gradiens kép (Ix) normalizált megjelenítése Y-irányú gradiens kép (Iy) normalizált megjelenítése Gradiens magnitúdó (Imagn) normalizált megjelenítése
  • Számítsuk ki a kép X- és Y-irányú gradiens képeit (Ix és Iy)!
  • Vegyük észre, hogy negatív értékek is előfordulhatnak az eredményben, ezért normalizált, [min, max][0, 255] tartományra alakított megjelenítésre van szükség! A homogén területen előforduló 0 (vagy a körüli) érték a középszürkék, a sötétek a negatívok, a világosak a pozitívok. Ezt figyelembe véve jól megfigyelhető, hol lépünk világosból területből és sötétbe és viszont.
  • Minden képponthoz határozzuk meg a gradiensvektor magnitúdóját (nagyságát)! Az X- és Y-komponenseket a parciális derivált képekből vegyük. A magnitúdó a vektor hossza, vagyis a komponensek négyzetösszegéből vont négyzetgyök lesz. Minél nagyobb az érték, annál erősebb az él az adott pontban. Kétféle módon számíthatjuk.
    • Pontosabb eredmény, de költséges a számítása. A Imagn = cv2.magnitude(Ix, Iy) függvényhívás elvégzi ezt a számítást.

      I_{magn}=\sqrt{I_x^2+I_y^2}

    • Pontatlanabb, de gyorsabban számítható:

      I_{magn}=\lvert I_x + I_y \rvert

    • Gradiensvektor irányának meghatározása (ha szükséges):

      \Theta = \arctan \frac{I_x}{I_y}

  • Küszöböljük a magnitúdóképet megfelelő küszöbértékkel, hogy csak az erős élek helyeit kapjuk meg bináris objektumként! Például az OpenCV-logo.png kép gradiens magnitúdójának küszöbölése 400 küszöbértékkel az alábbi eredményt adja.

Mire figyeljünk?

  • A konvolúció eredménye kivezethet a [0, 255] intenzitástartományból! Emiatt az eredmény kerüljön 32 bites lebegőpontos típusba!
  • A gradiens magnitúdókép lebegőpontos értékeket tartalmaz. Megjelenítéshez normalizáljuk a [0, 1] tartományba az értékeket!
  • Küszöböléskor az alkalmazandó küszöbérték erősen függ a képi tartalomtól! Megtehetjük például, hogy a maximális érték adott százalékánál történjen ez. A példaprogramjainkban a forráskód elején definiált MAGN_THRESH_PERCENT változó használható a százalékos érték megadására ([0, 1] tartományból választva).
  • Alacsony küszöbérték esetén a homályosabb éleknél vastag (több képpontos) éldetekciót kapunk. Ha ez nem megfelelő számunkra, mert vékony él pozíciókat szeretnénk, akkor ilyen esetben használjunk Laplace operátort vagy Canny éldetektort! A különböző vastagságú él detekciók jól megfigyelhetők az OpenCV-logo.png kép eredményén is.

OpenCV lehetőségek

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

Tetszőleges konvolúciós maszkot alkalmazhatunk a cv2.filter2d() függvénnyel, ahogyan a zajszűrés témakörnél már láttuk is.

Sobel operátor közvetlen végrehajtása

Első-, másod-, vagy harmadrendű derivált meghatározása a kiterjesztett Sobel operátorral.

dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])

dst Eredménykép
src Forráskép
ddepth Mint cv2.filter2D() függvénynél.
Itt célszerű cv2.CV_32FC1 értéket megadnuk.
dx X-irányú derivált rendje
dy Y-irányú derivált rendje
ksize Sobel kernel mérete. 1, 3, 5, 7 értékű lehet.
-1 érték esetén a Scharr kernellel történik a konvolúció!
scale Opcionális skálázó érték a számított derivált értékhez.
delta Opcionális érték, ami a súlyozott összeghez kerül hozzáadásra.
borderType Extrapolációs módszer a kép határán.

Scharr operátor közvetlen végrehajtása

Első-, másod-, vagy harmadrendű derivált meghatározása a Scharr operátorral.

dst = cv2.Scharr(src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]])

A paraméterek jelentése megegyezik a cv2.Sobel() függvényével. Figyeljük meg, hogy nincs ksize paraméter, vagyis csak a fenti 3x3 méretű maszkot tudjuk használni!

A függvény eredménye megegyezik a cv2.Sobel() függvény ksize=-1 paraméterezésű hívásával.

07_02_a_Sobel_filter2d.py

Az X- és Y-irányú diszkrét gradienseket konvolúcióval határozzuk meg. A gradiens képekből magnitúdó képet számítunk. Külön függvény használunk a képek normalizálására a megjelenítéshez.

import cv2
import numpy as np

MAGN_THRESH_PERCENT = 0.2

img = cv2.imread('OpenCV-logo.png', cv2.IMREAD_GRAYSCALE)



# Kép normalizálása és megjelenítése

def display_image(window, image):
disp = cv2.normalize(image, None, 0, 255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)
cv2.imshow(window, disp)



Gx = np.array([

[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]])

img_dx = cv2.filter2D(img, cv2.CV_32F, Gx)
display_image('Ix', img_dx)

Gy = np.array([
[1, 2, 1],
[0, 0, 0],
[-1, -2, -1]])

img_dy = cv2.filter2D(img, cv2.CV_32F, Gy)
display_image('Iy', img_dy)

img_gradient_magnitude = cv2.magnitude(img_dx, img_dy)
display_image('Gradient magnitude', img_gradient_magnitude)

magn_th = np.amax(Imagn) * MAGN_THRESH_PERCENT
print('magn_th =', magn_th)
_, ImagnTh = cv2.threshold(Imagn, magn_th, 1.0, cv2.THRESH_BINARY)
display_image('Thresholded gradient magnitude', ImagnTh)

cv2.waitKey(0)

cv2.destroyAllWindows()

07_02_b_Sobel.py

Jelen változatban ugyanazt az eredményt kapjuk, mint az előző példaprogramban. Itt viszont egyszerűbb nagyobb maszkméretre átállni, mert a maszkokat a függvény számítja ki, nem nekünk kell definiálni.


import cv2

import numpy as np

MAGN_THRESH_PERCENT = 0.2

img = cv2.imread('OpenCV-logo.png', cv2.IMREAD_GRAYSCALE)



# Kép normalizálása és megjelenítése
def display_image(window, image):
  disp = cv2.normalize(image, None, 0, 255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8UC1)

  cv2.imshow(window, disp)


# ksize = -1 # Scharr kernel

ksize = 3 # 3x3 Sobel
# ksize = 5 # 5x5 Sobel

img_dx = cv2.Sobel(img, cv2.CV_32FC1, 1, 0, None, ksize)

display_image('Ix', img_dx)

img_dy = cv2.Sobel(img, cv2.CV_32FC1, 0, 1, None, ksize)
display_image('Iy', img_dy)

img_gradient_magnitude = cv2.magnitude(img_dx, img_dy)
display_image('Gradient magnitude', img_gradient_magnitude)

magn_th = np.amax(Imagn) * MAGN_THRESH_PERCENT
print('magn_th =', magn_th)
_, ImagnTh = cv2.threshold(Imagn, magn_th, 1.0, cv2.THRESH_BINARY)
display_image('Thresholded gradient magnitude', ImagnTh)

cv2.waitKey(0)

cv2.destroyAllWindows()

07_02_c_Sobel_tb.py

Ez előző program interaktív változata, ahol a gradiens magnitúdó küszöbölése csúszkával állítható.

Sobel demó tesztelése gradiensvektor megjelenítéssel

Próbáljuk ki a 07_02_d_Sobel_magnitude_visualizer.py példaprogramot!

  • Használjunk többféle bementi képet (Pl. bináris, ahol erős vízszintes, függőleges és ferde élek találhatók (tree_binary.png, tree_blur01.png, tree_blur_02.png); fotók)!
  • Vizsgáljuk meg az X- és Y-irányú gradiens képeket, a magnitúdó képet, és a küszöbölt élképet!
  • Mozgassuk az egeret az eredeti képet tartalmazó ablakban! Vizsgáljuk meg a vörös színnel megjelenő gradiensvektor vizualizációt!
  • Értelmezzük a látottakat!

    

Néhány eredmény a tree_blur_02.png kép esetén:

   

A program elején a SHOW_CONCATENATED_RESULT kapcsolót True értékre állítva egy közös ablakban láthatjuk a képeket. Ezen együtt láthatjuk az aktuális mutató pozíción elérhető X és Y gradiens értékeket, valamint az ezek által meghatározott gradiensvektort. (Ne feledjük: a koordináta-rendszer origója a kép bal felső sarka, az X tengely jobbra, az Y tengely lefelé mutat.)