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.

A blob detection illustrated against a binary threshold mask. The left panel shows a tilted oval mask of passing pixels. The right panel shows the same mask annotated with the axis-aligned bounding box drawn around it, the centroid marked with a cross in the middle, a dashed minimum-area rotated rectangle hugging the oval at its true angle, and the major-axis line through the centroid pointing along the oval's long direction.

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)