Skip navigation

Régiónövelés

Működési elve

Az OpenCV implementáció az alábbi lehetőségekkel rendelkezik.

Fő lépések

  • Egy kiindulási pont szükséges, amely a szegmens része.
  • A szegmens elemeinek 4- vagy 8-szomszédságát vizsgálva amennyiben a szomszéd teljesíti a hasonlósági kritériumot, akkor hozzávesszük a szegmenshez és az ő szomszédait is megvizsgáljuk.

Hasonlósági kritérium lehetőségek

  • Globális eltérés: A kiindulás pont és a vizsgált pont közötti eltérés egy megadott tartományon belül van.
  • Lokális eltérés: A vizsgált pont és objektumhoz tartozó szomszédja közötti eltérés egy megadott tartományon belül van.

Az algoritmus működésének példákon keresztüli, részletes magyarázata az oldal utolsó blokkjában olvasható.

A szakirodalomban a módszer számos további változata megtalálható. A hasonlóságot számíthatnánk akár a szegmenst éppen alkotó képpontokértékek átlagaként, az eltérést pedig lehetne a szórás értékkel súlyozni. Egy ilyen megközelítés esetén akár több pontból álló kiindulási pontlistánk is lehetne. Ezeket egyelőre nem valósítja meg az OpenCV implementáció.

OpenCV floodFill

A régiónövelést OpenCV-ben a floodFill() függvénnyel végezhetjük.

  • Szürkeárnyalatos és színes képre is működik. Ez utóbbi esetben csatornánként külön kell megadnunk alsó és felső eltérési küszöbértéket. A kritériumoknak minden csatornán teljesülni kell.
  • A növelési kritériumnak megfelelő pontokat a megadott értékűre vagy színűre színezi.
  • A kitöltött régiót egy maszk képben is visszaadja. Megkapjuk, hogy hány pont került a régióba.
  • A maszk képet nekünk kell előzetesen létrehoznunk! A méretére oda kell figyelni (magasság + 2, szélesség + 2)! A maszk képben előzetesen is helyezhetünk el értékeket. A nem 0 értékeket nem vizsgálja a függvény.

A függvény fejléce az alábbi:

retval, image, mask, rect = cv2.floodFill(image, mask, seedPoint, newVal[, loDiff[, upDiff[, flags]]])

retVal A végrehajtás során a régióhoz hozzáadott képpontok száma.
image Bemeneti szegmentálandó kép. 1 vagy 3 csatornás, valamint 8-bites egész, vagy float típusú kép lehet. A függvény megváltoztatja a kép tartalmát, a régió pontokat a megadott színre állítja. Kivéve, ha a FLOODFILL_MASK_ONLY flag-et is használjuk, ez esetben csak a maszk változik.
mask

A megfelelő működéshez szükséges maszk kép, amit előzetesen létre kell hoznunk. Mérete 2 képponttal szélesebb és magasabb kell legyen a bemeneti kép méreténél! Ezen a maszk képen a szélső képpontokat ugyanis technikai okokból kitölti a függvény. A módosított maszk képet eredményként is megkapjuk.

A kitöltés nem halad át a maszkon található nem 0 értékeken!

rect A változott régió befoglaló téglalapja.
seedPoint Kiindulási pont.
newVal Képbe írandó érték. Szürkeárnyalatos esetben egy skalár, színes kép esetén egy felsorolási objektum kell legyen.
loDiff Alsó eltérési küszöbérték. Többcsatornás bemenet esetén csatornánként külön értéket kell megani felsorolási objektumként, pl. (loDiff_b, loDiff_g, loDiff_r).
upDiff Felső eltérési küszöbérték. Többcsatornás bemenet esetén csatornánként külön értéket kell megani felsorolási objektumként, pl. (upDiff_b, upDiff_g, upDiff_r).
flags

Működést befolyásoló jelzőbitek. Az első 8 bit a szomszédság típusát adja, ami 4 vagy 8 értékű lehet. A következő 8 bit 1-255 közötti értéket kaphat, ami a maszk képbe írandó értéket jelenti. 

Az alsó 16 bit értékei logikai VAGY művelettel (Python | operátora) kibővíthetők az alábbi kapcsolókkal:

  • FLOODFILL_FIXED_RANGE: Ha megadjuk, akkor a kiindulási pont értékéhez történik a hasonlítás. Ha nem adjuk meg, akkor a szomszédsághoz.
  • FLOODFILL_MASK_ONLY: Csak a maszk tartalma változik, a bementi kép nem.

Dokumentáció:

Régiónövelés példaprogramok

10_04_floodfill.py

  • Bal egérkattintással adható meg a kiindulási pont. Újabb pont megadása új szegmentálást indít, az előző törlésével.
  • Interaktívan állítható az alsó és felső eltérés értéke. Módosításkor a korábban megadott kiindulási pontból újraindítja a szegmentálást. Így jól tesztelhetjük a küszöbök hatását.
  • Billentyűlenyomással állítható működési módok:
    • Globális (kiindulási ponthoz képesti) vagy lokális (szomszédsághoz képesti) legyen az eltérés számítása (f és g).
    • Szomszédság (4 vagy 8) váltása.

10_05_ffilldemo.py

  • Egérkattintással adható meg a kiindulási pont. Újabb pont megadása új szegmentálást indít, az előzők megtartásával.
  • Interaktívan állítható az alsó és felső eltérés értéke. A módosítás viszont csak a később indításra kerülő szegmentálásokra van hatással.
  • Billentyűlenyomással állítható működési módok:
    • Külön maszk kép használata vagy kikapcsolása (m).
    • Globális vagy lokális legyen az eltérés számítása (f és g).
    • Nulla eltérésű verzió használata (s).
    • Színes vagy szürke kép (c).
    • Eredeti kép visszaállítása (r).
    • Szomszédság (4 vagy 8) váltása.

Eredmény több kiindulási pontból indulva, az alapbeállítások használatával (újraszínezett eredmény és bináris maszk):

 

Magyarázat a működéshez

Kiindulási képmátrix

Az algoritmus működését egy 9x9 méretű szürkeárnyalatos képen követjük, amit felnagyítva ábrázolunk, hogy képpont szinten lássuk. A kék színű rács a képpont határokat jelöli.

A cellákba írt számértékek jelzik a szürkeségi szinteket. Az egyforma intenzitásértékeket nem jelöltük mindet külön. A fekete képpontok 0 értékűek.

Ezt a mátrixot létrehozhatjuk az alábbi Numpy függvényhívással:

arr = np.array([[0,   0,   0, 100,   0,   0,   0,   0,   0],
[0, 0, 100, 100, 100, 0, 0, 250, 0],
[0, 100, 100, 100, 100, 100, 0, 0, 0],
[150, 150, 150, 150, 150, 150, 150, 0, 0],
[0, 200, 200, 200, 200, 200, 0, 0, 0],
[0, 200, 250, 200, 250, 200, 0, 0, 0],
[0, 200, 200, 200, 200, 200, 0, 200, 200],
[0, 200, 200, 200, 200, 200, 0, 200, 200],
[0, 200, 200, 250, 200, 200, 0, 200, 200]], dtype=np.uint8)


print(arr)

Maszk inicializálás

A mask egy 11x11 méretű, 0 értékeket tartalmazó tömb:

mask = np.zeros((arr.shape[0] + 2, arr.shape[1] + 2), dtype=np.uint8)
print(mask)

Első algoritmus

A vizsgálandó intenzitásértéket mindig a kiindulás pont értékéhez viszonyítjuk (FLOODFILL_FIXED_RANGE). Az alsó (loDiff) és felső eltérés (upDiff) értékét 30-ra állítjuk. 4-szomszédságot vizsgálunk.

retval, arr, mask, rect = cv2.floodFill(arr, mask, (4, 4), 255, 30, 30, flags=4 | cv2.FLOODFILL_FIXED_RANGE)
print(retval)
print(arr)
print(mask)
print(rect)

A kiindulási pontunk (seedPoint) a (4, 4) koordinátájú, amit vörös körrel jelölünk.

A négy vizsgálandó szomszédot a vörös négyzetek jelölik.

A kiindulási pont bal és jobb szomszédai teljesítik a kritériumot, mert belül esnek a [170, 230] intenzitástartományon. (A seedPoint intenzitásértéke 200, ahogyan a bal és jobb szomszédoké is, és mivel lefelé és felfelé maximum 30 értékkel térhetnek el, ami ezekre igaz.) Ezeket zöld körrel jelöljük.

A felső és alsó szomszédok kívül esnek a ±30 tartományon a 150 és 250 értékeikkel. Ezeket vörös X-szel jelöljük, nem kerülnek további vizsgálatra.

A bal és jobb szomszédok szomszédainak vizsgálata. Az ebbe kerülő képpontok sárga kerettel ábrázolódnak.

A zöld körrel jelöltek teljesítik a kritériumot, felkerülnek a további vizsgálat listájára. Az X-szel jelöltek nem.

A vizsgálandó listára korábban már felkerült képpontokat nem vizsgáljuk újra.

Az algoritmus akkor ér véget, ha a vizsgálati listára került összes képpont szomszédságát átnéztük, és nem találtunk további pontot.

Az algoritmus eredményét látjuk az ábrán, az előzőleg alkalmazott jelölésekkel.

Látható, hogy lehetnek olyan pontok a képen, amelyek nem kerülnek vizsgálatra, mert nem vezet út hozzájuk, külön komponenst alkotnak, hiába egyezne meg az intenzitásértékük a kiindulási pontéval.

22 képpont változott meg (kiindulási pont + a zöld körrel jelzettek), amit a retval értéke is alátámaszt.

Második algoritmus

A vizsgálandó intenzitásértéket továbbra is a kiindulás pont értékéhez viszonyítjuk (FLOODFILL_FIXED_RANGE). Az alsó eltérés értékét (loDiff) magasabbra, 60-ra állítjuk, a felső eltérést (upDiff) 30 értéken hagyjuk. 4-szomszédságot vizsgálunk.

retval, arr, mask, rect = cv2.floodFill(arr, mask, (4, 4), 255, 60, 30, flags=4 | cv2.FLOODFILL_FIXED_RANGE)
A kiindulási pont felső szomszédja is teljesíti a kritériumot, mert benne van a [140, 230] tartományban (ne feledjük, -60 és +30 értékűek most a határok).

A felső szomszéd bal és jobb szomszédai is jók.

A felső szomszéd felső szomszédja viszont nem, mert a 100 érték túl nagy eltérést mutat a kiindulási pont 200 értékéhez képest.

Az algoritmus ezen paraméterezésének végeredménye.

A vizsgált képpontokat jelző sárga körvonalakat most nem ábrázoltuk, a zöld kör és vörös X jelölésekből egyértelmű, mivel dolgoztunk.

29 képpont változott.

Harmadik algoritmus

A vizsgálandó intenzitásértéket a szomszéd képpont értékéhez viszonyítjuk, nem a kiindulási pontéhoz (FLOODFILL_FIXED_RANGE nem kerül beállításra). Az alsó és felső eltérés értéke megegyezik a második algoritmusével (-60 és +30 értékek). 4-szomszédságot vizsgálunk.

retval, arr, mask, rect = cv2.floodFill(arr, mask, (4, 4), 255, 60, 30, flags=4)
A felső szomszéd most is teljesíti a kritériumot, mint az előző esetben is.
Az új pontok vizsgálatakor nem a kiindulási pont (vörös kör), hanem az aktuális szomszéd (sárga kör) intenzitásértéke kerül összehasonlításra. Emiatt a felső szomszéd felső szomszédja is felkerül a vizsgálandó pontok listájára (a 150 és a 100 értékek között 60-nál kisebb a differencia). Ahogyan az ő 100 értékű szomszédai is.
A harmadik algoritmus eredménye. 38 képpont változott.