5.25. Pronalaženje mrlja

Pragom je snimljena sličica pretvorena u binarnu masku: svaki piksel ili prolazi test praga ili ne prolazi. To odgovara na pitanje koje boje važne za aplikaciju se pojavljuju u sceni, ali ne i gdje – maska je samo more jedinica i nula. Sljedeći korak je detekcija mrlja: prolazak kroz masku, pronalaženje povezanih područja prolazećih piksela i vraćanje svakog od njih kao objekta s položajem, veličinom, orijentacijom i ostalim svojstvima na koja aplikacija može reagirati.

find_blobs() je glavna metoda za taj korak i najčešća je ulazna točka u svijet objekata rezultata modula image. Praćenje obojene loptice, slijeđenje crte naslikane na podu, brojanje koliko svijetlih točaka termalni senzor vidi, odlučivanje je li plavi LED upaljen ili ugašen – isti poziv pokriva sve njih. Ulazi se mijenjaju (pragovi, pretraživano područje, filtri primijenjeni na rezultat), ali obrazac poziva je isti.

5.25.1. Osnovni poziv

find_blobs prima popis pragova i vraća popis objekata rezultata mrlja:

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))

Svaka n-torka praga ima isti oblik kao pragovi proslijeđeni metodi binary() – šest unosa (l_lo, l_hi, a_lo, a_hi, b_lo, b_hi) za RGB565 sliku (granice su u LAB-u), dva unosa (lo, hi) za sliku u sivim tonovima. U jednom pozivu može se dati do 32 praga, što metodu find_blobs() čini tako fleksibilnom: crveni, zeleni i plavi svjetionici mogu se pratiti istovremeno, svaki pridonoseći svojim mrljama vraćenom popisu, a svojstvo code svake mrlje označava kojem pragu odgovara.

Pozivi draw_rectangle() i draw_cross() iznad označavaju snimljenu sličicu za pregled u IDE-u. Rezultat mrlje već nosi b.rect (granični okvir kao 4-torku) te b.cx / b.cy (cjelobrojni centroid), pa je crtanje detekcije natrag u sličicu pitanje dvaju poziva metoda.

5.25.2. Što rezultat sadrži

Svaka Blob je n-torka atributa koja objedinjuje sve što je detektor izmjerio o području. Svojstva se dijele u četiri skupine.

Skupina graničnog okvira i centroidax, y, w, h, rect, cx, cy, cxf, cyf – opisuje položaj mrlje. rect je 4-torka (x, y, w, h) koju metode crtanja očekuju; cx i cy su centroid u cjelobrojnim pikselskim koordinatama; cxf i cyf su centroid u sub-pikselskim float koordinatama, korisni kada uzvodna kalibracija mari za razlomljene položaje.

Deskriptori oblikapixels, area, density, perimeter, roundness, elongation, compactness, rotation – opisuju kako mrlja izgleda. pixels je broj prolazećih piksela; area je površina graničnog okvira poravnatog s osima (w * h); density je omjer tih dviju vrijednosti, koji se približava 1.0 za puni pravokutnik i pada prema 0.0 za tanak dijagonalni potez. roundness i compactness oboje ocjenjuju koliko je mrlja okrugla, iz različitih geometrijskih kutova (roundness iz momenata drugog reda, compactness iz omjera opsega i površine); elongation je 1.0 - roundness radi praktičnosti. rotation je orijentacija glavne osi u radijanima, koja je najtočnija na izduženim mrljama, a postaje šumna na gotovo okruglima (dvosmislena os nema dobro definiran smjer).

Metapodaci praga i spajanjacode, count – označavaju koji prag odgovara i koliko je izvornih mrlja spojeno u vraćenu. code je 32-bitna bitmapa s jednim postavljenim bitom po odgovarajućem pragu (jedan prag daje code == 1; spojena višebojna mrlja može imati postavljeno više bitova); count je 1 osim ako merge=True nije spojio nekoliko detekcija u jednu.

Skupina kutovacorners, min_corners – daje rotiranu geometriju mrlje. corners je 4-torka ekstrema (x, y) izvučenih iz konture mrlje, poredanih u smjeru kazaljke na satu od gornjeg lijevog kuta; min_corners je 4-torka kutova za rotirani pravokutnik najmanje površine koji obuhvaća mrlju. Pravokutnik najmanje površine je tijesno prianjanje; rect poravnat s osima je labavo prianjanje poravnato s pikselskom mrežom. Oba su korisna ovisno o tome treba li nizvodni stupanj orijentiran okvir ili običan.

Detekcija mrlje prikazana na binarnoj masci praga. Lijevi panel prikazuje nagnutu ovalnu masku prolazećih piksela. Desni panel prikazuje istu masku označenu graničnim okvirom poravnatim s osima nacrtanim oko nje, centroidom označenim križem u sredini, isprekidanim rotiranim pravokutnikom najmanje površine koji prianja uz oval pod njegovim stvarnim kutom te linijom glavne osi kroz centroid koja pokazuje uzduž dugog smjera ovala.

Mrlja nosi granični okvir poravnat s osima (rect, x, y, w, h), centroid (cx, cy ili sub-pikselski cxf, cyf), rotirani pravokutnik najmanje površine (min_corners uz rotation) te opcionalne linije glavne / sporedne osi izračunate pomoćnim funkcijama na razini modula u nastavku.

5.25.4. Spajanje preklapajućih mrlja

merge=True naknadno obrađuje popis rezultata kako bi spojio mrlje čiji se granični pravokutnici preklapaju. Prirodna upotreba je detekcija cilja čiju boju kamera vidi kao više područja s pragom zbog zrcalnih odsjaja, linija sjene ili neujednačenog osvjetljenja preko objekta: jedna crvena loptica može se vratiti kao tri ili četiri male crvene mrlje koje, uzete zajedno, tvore loptu. S merge=True tri mrlje postaju jedna velika mrlja, rect pokriva uniju, code je bitovni OR kodova spojenih mrlja (pa višebojno spajanje označava koje su boje pridonijele), a count izvještava koliko je izvornih mrlja spojeno.

margin povećava ili smanjuje granične pravokutnike prije testa preklapanja. S margin=2 mrlje čiji granični pravokutnici dođu unutar 2 piksela jedan od drugoga ipak se spajaju; s margin=-2 spajaju se samo mrlje čiji se granični pravokutnici preklapaju za barem 2 piksela. Prirodno podešavanje: pozitivna margina za rukovanje mrljama koje je prag razbio na susjedne dijelove; negativna margina za držanje tijesno grupiranih različitih objekata odvojenima.

merge_cb izvodi se na svakom kandidatskom paru prije nego što se spajanje dogodi. Povratni poziv prima dvije mrlje i vraća True da dopusti spajanje ili False da ga spriječi. Ovo je pravi alat za unakrsnu provjeru spajanja koja geometrijsko pravilo promaši – na primjer, odbijanje spajanja dviju mrlja čiji se kutovi rotation razlikuju više od praga ili odbijanje spajanja male mrlje u mnogo veću ako je mala samo mrljica.

5.25.5. Projekcijski histogrami

x_hist_bins_max i y_hist_bins_max pridružuju opcionalne projekcijske histograme svakoj mrlji. Projekcijski histogram je broj prolazećih piksela uzduž jedne osi: histogram X-osi zbraja prolazeće piksele po stupcu unutar graničnog okvira mrlje, a histogram Y-osi zbraja po retku. Oba zadano iznose nulu – histogrami se ne računaju osim ako se ne navede max različit od nule, jer bi inače dodavali posao svakoj detekciji.

Kada se izračunaju, histogrami pružaju jeftin 1-D signal na kojem aplikacija može pokrenuti daljnju analizu: otkrivanje položaja okomite pruge unutar mrlje, pronalaženje točke prijeloma dvobojnog cilja, brojanje koliko se praznina pojavljuje uzduž duge osi. Popunjavaju se kao svojstva x_hist_bins i y_hist_bins na svakoj Blob.

5.25.6. Dodatni geometrijski pomoćnici

Pregršt daljnjih geometrijskih mjera postoji kao funkcije na razini modula koje primaju mrlju i vraćaju traženu mjeru:

5.25.7. Automatsko učenje praga

Detektor mrlja dobar je samo onoliko koliko i pragovi s kojima se izvodi, a posao pronalaženja pravog praga za boju cilja sam je za sebe problem. Dva uobičajena obrasca smanjuju taj posao.

Prvi je interaktivni odabir u IDE-u: snimite sličicu, povucite pravokutnik oko primjera ciljne boje i pustite IDE-ov uređivač praga da izvijesti o LAB granicama koje vidi. Te granice spuste se u skriptu kao pragovi metode find_blobs() i detektor je spreman.

Drugi je programsko automatsko učenje: kalibracijska rutina koja se izvodi na kameri snima sličicu, uzima histogram poznate mrlje gdje je cilj (get_histogram() s roi=) i očitava raspon vrijednosti mrlje s histograma pomoću get_percentile(). 5. percentil postavlja donju granicu svakog kanala, a 95. njegovu gornju granicu, zanemarujući zalutale izdvojene piksele na oba kraja. Na RGB565 slici jedan poziv percentila izvještava sva tri LAB kanala odjednom, pa dva poziva proizvode šest brojeva koje find_blobs() očekuje:

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)