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 tyngdpunkt – x, 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.
Formdeskriptorerna – pixels, 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 sammanslagning – code, 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örn – corners, 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 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.3. Filtrera sökningen¶
En fångad bildruta innehåller vanligtvis pixlar som matchar tröskelvärdet av andra skäl än det objekt applikationen bryr sig om: spegelreflexer, avlägsna bakgrundsobjekt, bildbruspixlar som råkar hamna inom LAB-intervallet. Nyckelordsargumenten till find_blobs() är första försvarslinjen.
roi begränsar sökningen till ett område av bildrutan, på samma sätt som alla andra metoder i bildmodulen gör. En applikation som vet att objektet bara kan förekomma i den nedre halvan av synfältet skickar roi=(0, h//2, w, h//2) och ignorerar allt ovanför; den sparade tiden går tillbaka till bildfrekvensen.
area_threshold och pixels_threshold filtrerar båda bort blobbar som är för små för att bry sig om. area_threshold släpper blobbar vars begränsningsruta har färre pixlar i area än så (bra för att filtrera bort utspritt brus); pixels_threshold släpper blobbar som har färre godkända pixlar än så (bra för att filtrera bort blobbar som är stora men glesa, som ett tröskat punktmönster med en eller två matchande pixlar här och där). Båda har standardvärdet 10; att veva upp dem till hundratals för ett förgrundsobjekt som är några centimeter brett kastar bort varje gnutta småbrus.
x_stride och y_stride anger pixelsteget som skannern tar medan den letar efter en blob att börja spåra. Steg är inte spårningsupplösningen – spårningen följer alltid den faktiska blob-gränsen med enpixelsdetalj – men det styr hur snabbt skanningen hittar en startpixel. När blobbar är kända för att vara stora (ett knytnävsstort färgat mål en halvmeter från kameran, lätt hundra pixlar brett) skär x_stride=4, y_stride=4 skanningstiden till en sextondel utan någon praktisk förlust i detektering. När blobbar är små (en avlägsen LED-fyr, några pixlar bred) måste stegen ligga kvar på 1 för att undvika att kliva förbi dem helt. invert vänder på tröskeltestet: matchning blir icke-matchning och rutinen returnerar blobbar av underkända pixlar i stället.
threshold_cb är ett Python-återanrop som anropas på varje blob efter tröskling men innan den slutgiltiga resultatlistan byggs. Återanropet tar emot blobben och returnerar True för att behålla den eller False för att släppa den. Detta är platsen att tillämpa godtyckliga filter på Python-nivå på egenskaper som nyckelordsargumenten inte exponerar direkt – en minsta täthet, ett specifikt rotationsintervall, en anpassad kombination av kodbitar efter sammanslagning. Nyckelordsargumenten är filter i inbyggd kod och körs snabbt; återanropet körs i Python och är långsammare men obegränsat i vad det kan uttrycka.
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ära1.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 är1.0; taggiga eller skårade blobbar är lägre.image.get_major_axis_line()ochimage.get_minor_axis_line()returnerarLine-objekt längs blobbens huvud- och biaxel, härledda ur den roterade rektangeln med minsta area.image.get_enclosing_circle()returnerar enCirclesom 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 idraw_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)