5.25. Hledání blobů

Prahování proměnilo zachycený snímek na binární masku: každý pixel buď projde testem prahu, nebo neprojde. To odpovídá na otázku, které barvy, na nichž aplikaci záleží, se ve scéně objevují, ale ne kde – maska je jen moře jedniček a nul. Dalším krokem je detekce blobů: procházení masky, hledání souvislých oblastí procházejících pixelů a vrácení každé z nich jako objektu s pozicí, velikostí, orientací a dalšími vlastnostmi, podle kterých může aplikace jednat.

find_blobs() je tažnou metodou tohoto kroku a je nejběžnějším vstupním bodem do světa výsledkových objektů modulu image. Sledování barevného míče, následování čáry namalované na podlaze, počítání, kolik jasných bodů vidí termální senzor, rozhodování, zda modrá LED svítí nebo ne – totéž volání pokrývá je všechny. Vstupy se mění (prahy, prohledávaná oblast, filtry aplikované na výsledek), ale vzor volání je stejný.

5.25.1. Základní volání

find_blobs přijímá seznam prahů a vrací seznam výsledkových objektů blobů:

thresholds = [(30, 100, 15, 127, 15, 127)]  # LAB threshold for red
blobs = img.find_blobs(thresholds)

for b in blobs:
    img.draw_rectangle(b.rect, color=(255, 0, 0))
    img.draw_cross(b.cx, b.cy, color=(255, 0, 0))

Každá n-tice prahu má stejný tvar jako prahy předávané metodě binary() – šest položek (l_lo, l_hi, a_lo, a_hi, b_lo, b_hi) pro obraz RGB565 (meze jsou v LAB), dvě položky (lo, hi) pro obraz ve stupních šedi. V jediném volání lze zadat až 32 prahů, což činí metodu find_blobs() tak flexibilní: červené, zelené a modré majáky lze sledovat současně, každý přispívá svými vlastními bloby do vráceného seznamu a vlastnost code každého blobu identifikuje, kterému prahu odpovídal.

Volání draw_rectangle() a draw_cross() výše označí zachycený snímek pro náhled v IDE. Výsledek blobu již nese b.rect (ohraničující rámeček jako 4-tici) a b.cx / b.cy (celočíselný centroid), takže vykreslení detekce zpět do snímku jsou dvě volání metod.

5.25.2. Co výsledek obsahuje

Každý Blob je atributová n-tice, která sdružuje vše, co detektor o oblasti změřil. Vlastnosti se dělí do čtyř skupin.

Skupina ohraničujícího rámečku a centroidux, y, w, h, rect, cx, cy, cxf, cyf – popisuje pozici blobu. rect je 4-tice (x, y, w, h), kterou očekávají metody kreslení; cx a cy jsou centroid v celočíselných pixelových souřadnicích; cxf a cyf jsou centroid v subpixelových float souřadnicích, užitečných tam, kde předřazené kalibraci záleží na zlomkových pozicích.

Deskriptory tvarupixels, area, density, perimeter, roundness, elongation, compactness, rotation – popisují, jak blob vypadá. pixels je počet procházejících pixelů; area je plocha osově zarovnaného ohraničujícího rámečku (w * h); density je poměr obou, který se blíží 1.0 pro plný obdélník a klesá k 0.0 pro tenký diagonální tah. roundness a compactness obě hodnotí, jak je blob kulatý, z různých geometrických hledisek (roundness z momentů druhého řádu, compactness z poměru obvodu k ploše); elongation je pro pohodlí 1.0 - roundness. rotation je orientace hlavní osy v radiánech, která je nejpřesnější u protáhlých blobů a stává se zašuměnou u téměř kulatých (nejednoznačná osa nemá dobře definovaný směr).

Metadata prahu a sloučenícode, count – identifikují, kterému prahu blob odpovídal a kolik zdrojových blobů bylo sloučeno do vráceného. code je 32bitová bitová mapa s jedním nastaveným bitem na každý odpovídající práh (jeden práh dává code == 1; sloučený vícebarevný blob může mít nastaveno několik bitů); count je 1, pokud merge=True nesloučilo několik detekcí do jedné.

Skupina rohůcorners, min_corners – udává otočenou geometrii blobu. corners je 4-tice extrémů (x, y) vytažených z kontury blobu, seřazených ve směru hodinových ručiček od levého horního rohu; min_corners je 4-tice rohů otočeného obdélníku s minimální plochou, který blob obklopuje. Obdélník s minimální plochou je těsným přizpůsobením; osově zarovnaný rect je volným přizpůsobením zarovnaným s pixelovou mřížkou. Oba jsou užitečné podle toho, zda následující fáze potřebuje orientovaný rámeček, nebo prostý.

Detekce blobu znázorněná na binární prahové masce. Levý panel ukazuje nakloněnou oválnou masku procházejících pixelů. Pravý panel ukazuje tutéž masku označenou osově zarovnaným ohraničujícím rámečkem nakresleným kolem ní, centroidem označeným křížkem uprostřed, čárkovaným otočeným obdélníkem s minimální plochou těsně obepínajícím ovál pod jeho skutečným úhlem a čárou hlavní osy procházející centroidem směřující podél dlouhého směru oválu.

Blob nese osově zarovnaný ohraničující rámeček (rect, x, y, w, h), centroid (cx, cy nebo subpixelové cxf, cyf), otočený obdélník s minimální plochou (min_corners plus rotation) a volitelné čáry hlavní / vedlejší osy vypočítané pomocníky na úrovni modulu níže.

5.25.4. Slučování překrývajících se blobů

merge=True dodatečně zpracovává seznam výsledků a slučuje bloby, jejichž ohraničující obdélníky se překrývají. Přirozeným použitím je detekce cíle, jehož barvu kamera vidí jako několik naprahovaných oblastí kvůli zrcadlovým odleskům, stínovým liniím nebo nesourodému osvětlení napříč objektem: jeden červený míč se může vrátit jako tři nebo čtyři malé červené bloby, které dohromady vystihují míč. S merge=True se ze tří blobů stane jeden velký blob, rect pokrývá sjednocení, code je bitový OR kódů sloučených blobů (takže vícebarevné sloučení identifikuje, které barvy přispěly) a count udává, kolik zdrojových blobů bylo zkombinováno.

margin zvětšuje nebo zmenšuje ohraničující obdélníky před testem překrytí. S margin=2 se sloučí i bloby, jejichž ohraničující obdélníky se k sobě přiblíží na 2 pixely; s margin=-2 se sloučí pouze bloby, jejichž ohraničující obdélníky se překrývají alespoň o 2 pixely. Přirozené ladění: kladný margin pro zacházení s bloby, které práh rozbil na sousedící kusy; záporný margin pro udržení těsně seskupených odlišných objektů odděleně.

merge_cb se spustí na každém kandidátním páru, než dojde ke sloučení. Callback obdrží dva bloby a vrátí True pro povolení sloučení nebo False pro jeho zabránění. Toto je správný nástroj pro křížovou kontrolu sloučení, která geometrické pravidlo míjí – například odmítnutí sloučení dvou blobů, jejichž úhly rotation se liší o více než práh, nebo odmítnutí sloučení malého blobu do mnohem většího, pokud je malý blob jen skvrnka.

5.25.5. Projekční histogramy

x_hist_bins_max a y_hist_bins_max připojují ke každému blobu volitelné projekční histogramy. Projekční histogram je počet procházejících pixelů podél jedné osy: histogram osy X sčítá procházející pixely na sloupec uvnitř ohraničujícího rámečku blobu a histogram osy Y sčítá na řádek. Oba mají výchozí hodnotu nula – histogramy se nepočítají, pokud není zadáno nenulové max, protože by jinak přidávaly práci ke každé detekci.

Když jsou vypočítány, histogramy poskytují levný 1-D signál, na kterém může aplikace provádět další analýzu: detekci pozice svislého pruhu uvnitř blobu, hledání zlomu dvoubarevného cíle, počítání, kolik mezer se objeví podél dlouhé osy. Jsou naplněny jako vlastnosti x_hist_bins a y_hist_bins na každém Blob.

5.25.6. Další geometričtí pomocníci

Hrstka dalších geometrických měr existuje jako funkce na úrovni modulu, které přijímají blob a vracejí požadované měření:

  • image.get_solidity() vrací plnost (solidity) blobu – pixely vydělené plochou konvexního obalu. Plná vyplněná oblast je blízko 1.0; blob s konkávnostmi (podkova, ruka s roztaženými prsty) klesá výrazně níže.

  • image.get_convexity() vrací konvexitu – obvod konvexního obalu vydělený obvodem blobu. Dokonale konvexní blob je 1.0; zubaté nebo zářezem opatřené bloby jsou nižší.

  • image.get_major_axis_line() a image.get_minor_axis_line() vracejí objekty Line podél hlavní a vedlejší osy blobu, odvozené z otočeného obdélníku s minimální plochou.

  • image.get_enclosing_circle() vrací Circle, který blob obklopuje – užitečné, když následující fáze chce kruh ke kreslení nebo k porovnání.

  • image.get_enclosed_ellipse() vrací 5-tici (cx, cy, rx, ry, rotation) pro elipsu vepsanou do obdélníku s minimální plochou blobu. Hodnoty vstupují přímo do draw_ellipse().

5.25.7. Automatické naučení prahu

Detektor blobů je jen tak dobrý jako prahy, se kterými je spuštěn, a práce s nalezením správného prahu pro cílovou barvu je sama o sobě problémem. Tuto práci snižují dva běžné vzory.

Prvním je interaktivní výběr v IDE: zachyťte snímek, přetáhněte obdélník kolem příkladu cílové barvy a nechte editor prahů v IDE nahlásit meze LAB, které vidí. Tyto meze se vloží do skriptu jako prahy find_blobs() a detektor je připraven.

Druhým je programové automatické naučení: kalibrační rutina běžící na kameře zachytí snímek, vezme histogram známé plošky, kde se cíl nachází (get_histogram() s roi=), a odečte rozsah hodnot plošky z histogramu pomocí get_percentile(). 5. percentil nastaví dolní mez každého kanálu a 95. jeho horní mez, přičemž ignoruje zatoulané odlehlé pixely na obou koncích. Na obrazu RGB565 jedno volání percentilu nahlásí všechny tři kanály LAB najednou, takže dvě volání produkují šest čísel, která find_blobs() očekává:

h = img.get_histogram(roi=patch)
lo = h.get_percentile(0.05)
hi = h.get_percentile(0.95)
threshold = (lo.l_value, hi.l_value,
             lo.a_value, hi.a_value,
             lo.b_value, hi.b_value)