5.25. Hitta blobbar

Tröskling förvandlade den fångade bildrutan till en binär mask: varje pixel klarar antingen tröskeltestet eller inte. Det besvarar vilka färger som applikationen bryr sig om förekommer i scenen, men inte var – masken är bara ett hav av ettor och nollor. Nästa steg är blob-detektering: att vandra genom masken, hitta sammanhängande områden av godkända pixlar och returnera vart och ett som ett objekt med en position, en storlek, en orientering och de övriga egenskaper en applikation kan agera utifrån.

find_blobs() är arbetshästmetoden för det steget, och den är den vanligaste ingången till bildmodulens värld av resultatobjekt. Att spåra en färgad boll, följa en linje målad på golvet, räkna hur många ljusa fläckar en termisk sensor ser, avgöra om en blå LED är på eller av – samma anrop täcker dem alla. Indata förändras (tröskelvärdena, det genomsökta området, de filter som tillämpas på resultatet), men anropsmönstret är detsamma.

5.25.1. Grundanropet

find_blobs tar en lista med tröskelvärden och returnerar en lista med blob-resultatobjekt:

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

Varje tröskeltupel har samma form som de tröskelvärden som skickas till binary() – sex poster (l_lo, l_hi, a_lo, a_hi, b_lo, b_hi) för en RGB565-bild (gränserna anges i LAB), två poster (lo, hi) för en gråskalebild. Upp till 32 tröskelvärden kan anges i ett enda anrop, vilket är det som gör find_blobs() så flexibel: röda, gröna och blå fyrar kan spåras samtidigt, där var och en bidrar med sina egna blobbar till den returnerade listan, och varje blobs code-egenskap identifierar vilket tröskelvärde den matchade.

Anropen draw_rectangle() och draw_cross() ovan annoterar den fångade bildrutan för IDE-förhandsvisningen. Blob-resultatet bär redan med sig b.rect (begränsningsrutan som en 4-tupel) och b.cx / b.cy (heltalstyngdpunkten), så att rita in detekteringen tillbaka i bildrutan är två metodanrop.

5.25.2. Vad resultatet innehåller

Varje Blob är en attributtupel som packar ihop allt detektorn mätte om området. Egenskaperna delas in i fyra grupper.

Gruppen begränsningsruta och tyngdpunktx, y, w, h, rect, cx, cy, cxf, cyf – beskriver blobbens position. rect är 4-tupeln (x, y, w, h) som ritmetoderna förväntar sig; cx och cy är tyngdpunkten i heltalspixelkoordinater; cxf och cyf är tyngdpunkten i flyttalskoordinater med subpixelprecision, vilket är användbart när en tidigare kalibrering bryr sig om bråkdelspositioner.

Formdeskriptorernapixels, area, density, perimeter, roundness, elongation, compactness, rotation – beskriver hur blobben ser ut. pixels är antalet godkända pixlar; area är arean på den axeljusterade begränsningsrutan (w * h); density är förhållandet mellan de två, vilket närmar sig 1.0 för en solid rektangel och faller mot 0.0 för ett tunt diagonalt streck. roundness och compactness poängsätter båda hur rund blobben är, utifrån olika geometriska synvinklar (roundness från andra ordningens moment, compactness från förhållandet mellan omkrets och area); elongation är 1.0 - roundness för bekvämlighets skull. rotation är orienteringen på huvudaxeln i radianer, vilket är mest exakt på avlånga blobbar och blir brusigt på nästan runda (en tvetydig axel har ingen väldefinierad riktning).

Metadatan för tröskelvärde och sammanslagningcode, count – identifierar vilket tröskelvärde som matchade och hur många källblobbar som slogs samman till den returnerade. code är en 32-bitars bitmapp med en bit satt per matchande tröskelvärde (ett enskilt tröskelvärde ger code == 1; en sammanslagen flerfärgad blob kan ha flera bitar satta); count är 1 om inte merge=True kombinerade flera detekteringar till en.

Gruppen hörncorners, min_corners – ger blobbens roterade geometri. corners är 4-tupeln av (x, y)-ytterpunkter hämtade från blobbens kontur, sorterade medurs från övre vänstra hörnet; min_corners är 4-tupeln av hörn för den roterade rektangel med minsta area som omsluter blobben. Rektangeln med minsta area är den tighta passningen; den axeljusterade rect är den lösa passningen som ligger i linje med pixelrutnätet. Båda är användbara beroende på om ett senare steg behöver en orienterad ruta eller en vanlig.

En blob-detektering illustrerad mot en binär tröskelmask. Den vänstra panelen visar en lutande oval mask av godkända pixlar. Den högra panelen visar samma mask annoterad med den axeljusterade begränsningsrutan ritad runt den, tyngdpunkten markerad med ett kors i mitten, en streckad roterad rektangel med minsta area som omsluter ovalen vid dess sanna vinkel, samt huvudaxellinjen genom tyngdpunkten som pekar längs ovalens långa riktning.

En blob bär med sig den axeljusterade begränsningsrutan (rect, x, y, w, h), tyngdpunkten (cx, cy eller subpixel cxf, cyf), den roterade rektangeln med minsta area (min_corners plus rotation) och de valfria linjerna för huvud- och biaxel som beräknas av modulnivåhjälparna nedan.

5.25.4. Slå samman överlappande blobbar

merge=True efterbearbetar resultatlistan för att kombinera blobbar vars begränsningsrektanglar överlappar. Den naturliga användningen är att detektera ett mål vars färg kameran ser som flera tröskade områden på grund av spegelreflexer, skuggränser eller ojämn belysning över objektet: en enda röd boll kan komma tillbaka som tre eller fyra små röda blobbar som tillsammans spårar bollen. Med merge=True blir de tre blobbarna en stor blob, rect täcker unionen, code är den bitvisa ELLER-operationen av de sammanslagna blobbarnas koder (så att en flerfärgad sammanslagning identifierar vilka färger som bidrog), och count rapporterar hur många källblobbar som kombinerades.

margin växer eller krymper begränsningsrektanglarna före överlappningstestet. Med margin=2 slås blobbar vars begränsningsrektanglar kommer inom 2 pixlar från varandra ändå samman; med margin=-2 slås endast blobbar vars begränsningsrektanglar överlappar med minst 2 pixlar samman. Den naturliga avstämningen: positiv marginal för att hantera blobbar som tröskelvärdet bröt upp i intilliggande bitar; negativ marginal för att hålla tätt grupperade distinkta objekt åtskilda.

merge_cb körs på varje kandidatpar innan sammanslagningen sker. Återanropet tar emot de två blobbarna och returnerar True för att tillåta sammanslagningen eller False för att förhindra den. Detta är rätt verktyg för att dubbelkolla sammanslagningar som den geometriska regeln missar – till exempel att vägra slå samman två blobbar vars rotation-vinklar avviker med mer än ett tröskelvärde, eller att vägra slå samman en liten blob in i en mycket större om den lilla bara är fläckbrus.

5.25.5. Projektionshistogram

x_hist_bins_max och y_hist_bins_max fäster valfria projektionshistogram vid varje blob. Ett projektionshistogram är antalet godkända pixlar längs en axel: X-axelns histogram summerar godkända pixlar per kolumn inuti blobbens begränsningsruta, och Y-axelns histogram summerar per rad. Båda har standardvärdet noll – histogrammen beräknas inte om inte ett max skilt från noll anges, eftersom de annars skulle lägga till arbete till varje detektering.

När de beräknas tillhandahåller histogrammen en billig 1D-signal som en applikation kan köra vidare analys på: att detektera positionen för en vertikal rand inuti blobben, att hitta brytpunkten för ett tvåfärgat mål, att räkna hur många gap som förekommer längs den långa axeln. De fylls i som egenskaperna x_hist_bins och y_hist_bins på varje Blob.

5.25.6. Extra geometriska hjälpare

En handfull ytterligare geometriska mått finns som funktioner på modulnivå som tar en blob och returnerar det begärda måttet:

  • image.get_solidity() returnerar blobbens soliditet – pixlar dividerat med arean på det konvexa höljet. Ett solitt fyllt område ligger nära 1.0; en blob med konkaviteter (en hästsko, en hand med fingrarna spretande) faller långt under.

  • image.get_convexity() returnerar konvexiteten – det konvexa höljets omkrets dividerat med blobbens omkrets. En perfekt konvex blob är 1.0; taggiga eller skårade blobbar är lägre.

  • image.get_major_axis_line() och image.get_minor_axis_line() returnerar Line-objekt längs blobbens huvud- och biaxel, härledda ur den roterade rektangeln med minsta area.

  • image.get_enclosing_circle() returnerar en Circle som omsluter blobben – användbar när ett senare steg vill ha en cirkel att rita eller testa mot.

  • image.get_enclosed_ellipse() returnerar 5-tupeln (cx, cy, rx, ry, rotation) för en ellips inskriven i blobbens rektangel med minsta area. Värdena matas direkt in i draw_ellipse().

5.25.7. Automatisk inlärning av ett tröskelvärde

En blob-detektor är bara så bra som de tröskelvärden den körs med, och arbetet med att hitta rätt tröskelvärde för en målfärg är sitt eget problem. Två vanliga mönster minskar det arbetet.

Det första är interaktivt urval i IDE:n: fånga en bildruta, dra en rektangel runt ett exempel på målfärgen och låt IDE:ns tröskelvärdesredigerare rapportera de LAB-gränser den ser. Dessa gränser släpps in i skriptet som find_blobs()-tröskelvärden och detektorn är redo.

Det andra är programmatisk automatisk inlärning: en kalibreringsrutin som körs på kameran fångar en bildruta, tar ett histogram av en känd fläck där målet finns (get_histogram() med roi=), och läser av fläckens värdeintervall från histogrammet med get_percentile(). Den 5:e percentilen sätter varje kanals undre gräns och den 95:e dess övre gräns, och ignorerar enstaka avvikande pixlar i båda ändar. På en RGB565-bild rapporterar ett percentilanrop alla tre LAB-kanalerna samtidigt, så att de två anropen ger de sex tal som find_blobs() förväntar sig:

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)