Skip navigation

Kontúrok detektálása

Kontúr

Az OpenCV lehetőséget biztosít (pl. szegmentálással előállított) bináris képeken az objektumok körvonalának meghatározására, illetve a kontúrok képre rajzolására. Ha szürkeárnyalatos vagy színes képünk van, akkor a bináris bemenet előállításához szükséges előzetesen küszöbölést vagy (bináris) szegmentálást végezni a képen. Ha ezt nem tesszük, akkor hibaüzenetet nem kapunk, viszont a szürkeárnyalatos bemenetet binárisként kezeli az OpenCV: 0: háttérpont, >0: objektumpont.

A bináris képek megjelenítése, és a velük való maszkolási lehetőségek könnyű elérése miatt a jegyzet példáiban a 255 (fehér) intenzitásértéket használjuk az objektumpontokra.

Kontúrpontok azok az objektumpontok lesznek, amelyeknek van háttérpont szomszédja. (Az OpenCV dokumentáció nem részletezi, milyen szomszédsági relációt vesz figyelembe itt.)

Bemeneti bináris kép (contour_test_2.png) Detektált kontúrok (rárajzolt színes vonalak)

Figyeljük meg az alábiakat:

  • Bizonyos kontúrok másokat is magukban foglalnak: a fenti példában vörös a zöldet, a kék a sárgát és a lilát, a sárga a lilát. Az OpenCV arra is képes, hogy ezt a hierarchia információt is biztosítsa a számunkra, ha fel szeretnénk használni.
  • Az is látható, hogy egy összefüggő objektum komponensnek pontosan egy külső kontúrja van, míg az üregeihez tartozó belső kontúrokból annyi, ahány üreg van (vagyis akár egy sem). A példában a vörös, a kék és a lila kontúrok külsők, míg a zöld és a sárga belsők.

findContours() függvény

Angol nyelvű dokumentáció

Kontúrok keresése

contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])

contours

Eredmény kontúrok listája.

Kontúr: cv2.CHAIN_APPROX_NONE módszer esetén (x, y) koordinátákból álló Numpy tömb, amely az objektum határpontjait tartalmazza. A többi módszer reprezentációját itt most nem részletezzük.

hierarchy Kontúrok topológiai rendszere (melyek vannak egy topológiai szinten, melyik tartalmaz másokat).
image

Bemeneti kép. 8 bites, egycsatornás kell legyen. 0 értékek a hátteret, 0-tól különbözők az objektumpontokat jelentik.

OpenCV 3.2-nél régebbi verziók esetén a függvény megváltoztatja a bemeneti kép tartalmát, és a módosítás eredményét első visszaadott paraméterként meg is kapjuk (3 darab visszatérési értéke volt)!

Újabb OpenCV verziók esetén nem változik a bemenő képi tartalom, és csak 2 visszatérő értéket kapunk, a fentiek szerint.

mode

Kontúr keresés módszere.

cv2.RETR_EXTERNAL: Csak a legkülső objektumok külső kontúrjait kapjuk, a belsőket és az üregeiben található további komponensekét nem!
cv2.RETR_LIST: Kontúrok listája hierarchia információ nélkül (külső, belső, üregben foglalt együttesen).
cv2.RETR_CCOMP: Kontúrok kétszintű hierarchiába rendezve összefüggő komponensenként (CCOMP = Connected Component). Szülő: külső kontúr, gyerekek: belső üregek kontúrjai.
cv2.RETR_TREE: Kontúrok teljes hierarchiába rendezve.

method

Kontúr leírás módszere.

cv2.CHAIN_APPROX_NONE: A kontúron található összes pont koordinátájának listázása.
cv2.CHAIN_APPROX_SIMPLE: A kontúr vízszintes, függőleges és átlós részei csak végpontjaikkal megadva. Kevesebb memóriát foglal ez a reprezentáció.
cv2.CHAIN_APPROX_TC89_L1cv2.CHAIN_APPROX_TC89_KCOS: Kontúr közelítés a Teh-Chin algoritmussal.

offset Eltolási érték hozzáadása a kontúr pontjaihoz. ROI-ban detektált kontúrok teljes képen való megjelenítésénél hasznos.

Kontúrok hierarchiája

A cv2.findContours() a kontúrok tömbje mellett visszaadja azok hierarchia információját is, amit erősen befolyásol a kontúrkeresés módszere.

Az idx indexű kontúr hierarchia információja egy négy elemű tömb, amit így érhetünk el:

hierarchy[0][idx]

A legkülső tömbindex mindig [0]. A kontúr indexek [0]-tól értelmeződnek. A tömb elemeinek jelentése az alábbi táblázat szerinti.

hierarchy[0][idx][0] Az ugyenezen a hierarchia szintén lévő következő kontúr indexe. -1, ha nincs ilyen.
hierarchy[0][idx][1] Az ugyenezen a hierarchia szinten lévő előző kontúr indexe. -1, ha nincs ilyen.
hierarchy[0][idx][2] A kontúr első gyerek kontúrja (amit az aktuális magában foglal) indexe. -1, ha nincs ilyen.
hierarchy[0][idx][3] A kontúr szülő kontúrja (amin belül helyezkedik el az aktuális) indexe. -1, ha nincs ilyen.

Kontúrok képmátrixba rajzolása

Az OpenCV segédfüggvényt biztosít a cv2.findContours() függvény által visszaadott kontúr adatok képmátrixba rajzolására.

image = cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])

image Kép, amelyikre a kontúr rajzok kerülnek. Eredményül is ezt kapjuk vissza.
contours A findContours() által előzetesen előállított kontúrok tömbje.
contourIdx Melyik sorszámú kontúrt rajzoljuk?
Negatív érték esetén az összeset.
color Kontúr rajzolt színe.
thickness Kontúr rajzolt vonalvastagsága.
Ha negatív értéket adunk meg, akkor kitölti a belső területet!
lineType

Kontúr rajzolt vonaltípusa.

Választható értékek: cv2.LINE_4, cv2.LINE_8, cv2.LINE_AA (4-összefüggő vonal, 8-összefüggő vonal, élelmosott vonal).

hierarchy findContours() által visszaadott kontúr hierarchia eredmény.
maxLevel

Rajzolandó kontúrok maximális hierarchia szintje. Használatakor át kell adni a findContours() által visszaadott hierarchy eredményt is!

0: csak a kért kontúr rajzolása.
1: a kért kontúr és a benne foglalt kontúrok rajzolása.
2: teljes hierarchia rajzolása.

offset Eltolási érték minden koordinátához. ROI-ban detektált kontúr rajzolásához hasznos.

Kontúr közelítés poligonnal

A következő függvénnyel lehetséges a kontúrok poligonnal való közelítése, megadott pontossággal. Így kevesebb definiáló pontból álló, simább kontúrt kapunk, ami viszont esetleg nem illeszkedik tökéletesen az eredeti körvonal pontokra.

approxCurve = cv2.approxPolyDP(curve, epsilon, closed[, approxCurve])

curve A findContours() által előzetesen kiszámított kontúr eredmény. A kontúr lista egy elemét kell átatni.
approxCurve Közelítő poligon eredmény.
epsilon Maximális megengedett távolság a kontúr és a közelítése között.
closed Zárt görbéről van-e szó? Kontúr esetén igen, így True értéket adunk át.

11_03_findContours.py

A példaprogram a tesztkép betöltése után küszöböli azt, majd megkeresi a kontúrokat. A megtalált kontúrokat egyenként a képmátrixba rajzolja, és kiírja a kontúr tömbök méret és hierarchia információit is.

Teszteljük a kontúrkeresést más paraméterezéssel, más bementi képeken is!

import cv2

line_colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0), (0, 255, 255), (255, 0, 255), (255, 255, 0), (255, 255, 255)]

im = cv2.imread('contour_test_2.png')

imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
# contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# contours, hierarchy = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_TC89_L1)

print('Hierarchia:')
print(hierarchy)

print('Kontúrok száma:', len(contours))
for cntrIdx in range(0, len(contours)):
print(cntrIdx, ':', contours[cntrIdx].shape,
'Következő:', hierarchy[0][cntrIdx][0],
'; Előző:', hierarchy[0][cntrIdx][1],
'; Gyerek:', hierarchy[0][cntrIdx][2],
'; Szülő:', hierarchy[0][cntrIdx][3])

cv2.drawContours(im, contours, cntrIdx, line_colors[cntrIdx % 7], 3, cv2.LINE_4)
cv2.imshow('Contours', im)
cv2.waitKey(0)

cv2.destroyAllWindows()

Eredmények

A program néhány különböző paraméterezésű futásának eredményeit elemezzük.

Az első vizsgálat a kontúrkeresés mode paraméterére vonatkozik. A függvény által visszaadott kontúrok sorrendjének színkódolása az alábbi: vörös, zöld, kék, sárga, lila.

RETR_LIST RETR_EXTERNAL RETR_TREE

Minden kontúrt detektál, de a hierarchia információ csak a sorrendiséget jelzi.

Hierarchia (következő, előző, szülő gyerek sorrendben):
[[
[ 1 -1 -1 -1]
[ 2 0 -1 -1]
[ 3 1 -1 -1]
[ 4 2 -1 -1]
[-1 3 -1 -1]
]]

Csak a legkülső kontúrok detektálása. A hierarchia információ csak ezek sorrendiségét jelzi.

Hierarchia (következő, előző, szülő gyerek sorrendben):
[[
[ 1 -1 -1 -1]
[-1 0 -1 -1]
]]

Minden kontúrt detektál, a hierarchia információ tartalmazza az egymásban foglalásokat is.

Hierarchia (következő, előző, szülő gyerek sorrendben):
[[
[ 1 -1 -1 -1]
[ 2 0 -1 -1]
[ 3 1 -1 -1]
[ 4 2 -1 -1]
[-1 3 -1 -1]
]]

A kontúrkeresésnél megadhatjuk a kontúr reprezentáció módszerét (method paraméter) is. Ez a definiáló adatok mennyiségére van hatással. A következő táblázatban a RETR_TREE módon visszakapott kontúrlistával dolgozunk.

A kontúrok esetén a Numpy tömb shape attribútuma kerül kiírása. Az első érték a kontúrpontok darabszáma (Numpy mátrix soraiban). Minden sorban 1 adat szerepel (koordináta), amely 2 értékkel, (x, y) formában kerül megadásra. Figyeljünk arra, hogy mivel ezt az eredményt az OpenCV adja vissza, így a koordináták sorrendje az OpenCV (oszlop, sor) sorrendjét jelenti, ha használjuk!

CHAIN_APPROX_NONE CHAIN_APPROX_SIMPLE CHAIN_APPROX_TC89_L1
Kontúrok száma: 5
(232, 1, 2)
(89, 1, 2)
(784, 1, 2)
(308, 1, 2)
(134, 1, 2)
Kontúrok száma: 5
(112, 1, 2)
(56, 1, 2)
(10, 1, 2)
(152, 1, 2)
(61, 1, 2)
Kontúrok száma: 5
(56, 1, 2)
(14, 1, 2)
(8, 1, 2)
(56, 1, 2)
(32, 1, 2)

Az első módszer felsorolja az összes kontúrpontot (x, y) koordinátákkal. A második a vízszintes és függőleges szakaszok esetén csak a végpontokat tartalmazza. A harmadik egy hatékony szakirodalmi módszer eredménye, aminek a működését itt nem részletezünk.

A kék színnel kiemelt sor a fenti RETR_TREE módszer által visszaadott, kékkel jelölt kontúrra vonatkozik. Az első módszer 784 pontjához képest, mivel hosszú vízszintes és függőleges szakaszokból áll 10-re csökken a definiáló pontok száma már a CHAIN_APPROX_SIMPLE módszerrel is. A harmadik módszer általános esetben jóval hatékonyabb.