5.25. Blobs vinden

Drempelwaardebepaling zette het vastgelegde frame om in een binair masker: elke pixel slaagt voor de drempelwaardetest of niet. Dat beantwoordt welke kleuren waar de applicatie om geeft in de scène voorkomen, maar niet waar – het masker is slechts een zee van enen en nullen. De volgende stap is blob-detectie: het masker doorlopen, aaneengesloten gebieden van geslaagde pixels vinden, en elk daarvan teruggeven als een object met een positie, een grootte, een oriëntatie en de andere eigenschappen waarop een applicatie kan reageren.

find_blobs() is de werkpaardmethode voor die stap, en het is het meest gebruikte toegangspunt tot de wereld van resultaatobjecten van de image-module. Een gekleurde bal volgen, een op de vloer geschilderde lijn volgen, tellen hoeveel heldere plekken een thermische sensor ziet, beslissen of een blauwe LED aan of uit staat – dezelfde aanroep dekt al deze gevallen. De invoer verandert (de drempelwaarden, het doorzochte gebied, de filters die op het resultaat worden toegepast), maar het aanroeppatroon is hetzelfde.

5.25.1. De basisaanroep

find_blobs neemt een lijst met drempelwaarden en geeft een lijst met blob-resultaatobjecten terug:

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

Elke drempelwaarde-tuple heeft dezelfde vorm als de drempelwaarden die aan binary() worden doorgegeven – zes elementen (l_lo, l_hi, a_lo, a_hi, b_lo, b_hi) voor een RGB565-afbeelding (de grenzen zijn in LAB), twee elementen (lo, hi) voor een grijswaardenafbeelding. Tot 32 drempelwaarden kunnen in één enkele aanroep worden opgegeven, wat find_blobs() zo flexibel maakt: rode, groene en blauwe bakens kunnen gelijktijdig worden gevolgd, waarbij elk zijn eigen blobs bijdraagt aan de teruggegeven lijst, en de code-eigenschap van elke blob identificeert met welke drempelwaarde deze overeenkwam.

De bovenstaande aanroepen draw_rectangle() en draw_cross() annoteren het vastgelegde frame voor de IDE-voorbeeldweergave. Het blob-resultaat bevat al b.rect (het begrenzingsvak als 4-tuple) en b.cx / b.cy (het gehele zwaartepunt), dus de detectie terugtekenen in het frame is een kwestie van twee methode-aanroepen.

5.25.2. Wat het resultaat bevat

Elke Blob is een attribuut-tuple die alles bundelt wat de detector over het gebied heeft gemeten. De eigenschappen vallen in vier groepen uiteen.

De groep begrenzingsvak en zwaartepuntx, y, w, h, rect, cx, cy, cxf, cyf – beschrijft de positie van de blob. rect is de (x, y, w, h) 4-tuple die tekenmethoden verwachten; cx en cy zijn het zwaartepunt in gehele pixelcoördinaten; cxf en cyf zijn het zwaartepunt in subpixel-floatcoördinaten, nuttig wanneer een eerdere kalibratie om fractionele posities geeft.

De vormdescriptorenpixels, area, density, perimeter, roundness, elongation, compactness, rotation – beschrijven hoe de blob eruitziet. pixels is het aantal geslaagde pixels; area is de oppervlakte van het asgerichte begrenzingsvak (w * h); density is de verhouding tussen die twee, die 1.0 benadert voor een massieve rechthoek en daalt richting 0.0 voor een dunne diagonale streep. roundness en compactness scoren beide hoe rond de blob is, vanuit verschillende geometrische gezichtspunten (roundness vanuit de tweede-orde momenten, compactness vanuit de verhouding tussen omtrek en oppervlakte); elongation is voor het gemak 1.0 - roundness. rotation is de oriëntatie van de hoofdas in radialen, die het nauwkeurigst is bij langgerekte blobs en ruizig wordt bij vrijwel ronde (een dubbelzinnige as heeft geen goed gedefinieerde richting).

De drempelwaarde- en samenvoeg-metadatacode, count – identificeren welke drempelwaarde overeenkwam en hoeveel bronblobs er werden samengevoegd tot de teruggegeven blob. code is een 32-bits bitmap met één bit gezet per overeenkomende drempelwaarde (een enkele drempelwaarde geeft code == 1; een samengevoegde meerkleurige blob kan meerdere bits gezet hebben); count is 1 tenzij merge=True meerdere detecties tot één combineerde.

De groep hoekencorners, min_corners – geeft de geroteerde geometrie van de blob. corners is de 4-tuple van (x, y)-uitersten die uit de contour van de blob is gehaald, met de klok mee gesorteerd vanaf linksboven; min_corners is de 4-tuple van hoeken voor de geroteerde rechthoek met minimale oppervlakte die de blob omsluit. De rechthoek met minimale oppervlakte is de strakke pasvorm; de asgerichte rect is de losse pasvorm uitgelijnd met het pixelraster. Beide zijn nuttig, afhankelijk van of een volgende fase een georiënteerd vak of een gewoon vak nodig heeft.

Een blob-detectie geïllustreerd tegen een binair drempelwaardemasker. Het linker- paneel toont een gekanteld ovaal masker van geslaagde pixels. Het rechterpaneel toont hetzelfde masker geannoteerd met het asgerichte begrenzingsvak eromheen getekend, het zwaartepunt gemarkeerd met een kruis in het midden, een gestippelde geroteerde rechthoek met minimale oppervlakte die het ovaal onder zijn werkelijke hoek omsluit, en de hoofdas-lijn door het zwaartepunt die langs de lange richting van het ovaal wijst.

Een blob draagt het asgerichte begrenzingsvak (rect, x, y, w, h), het zwaartepunt (cx, cy of subpixel cxf, cyf), de geroteerde rechthoek met minimale oppervlakte (min_corners plus rotation), en de optionele hoofd- / nevenas-lijnen die worden berekend door de onderstaande hulpfuncties op moduleniveau.

5.25.4. Overlappende blobs samenvoegen

merge=True verwerkt de resultaatlijst achteraf om blobs te combineren waarvan de begrenzingsrechthoeken overlappen. Het natuurlijke gebruik is het detecteren van een doelwit waarvan de camera de kleur als meerdere gedrempelde gebieden ziet vanwege spiegelende lichtvlekken, schaduwlijnen of ongelijkmatige belichting over het object: een enkele rode bal kan terugkomen als drie of vier kleine rode blobs die samen de bal traceren. Met merge=True worden de drie blobs één grote blob, dekt de rect de vereniging, is de code de bitsgewijze OR van de codes van de samengevoegde blobs (dus een meerkleurige samenvoeging identificeert welke kleuren hebben bijgedragen), en rapporteert count hoeveel bronblobs er werden gecombineerd.

margin vergroot of verkleint de begrenzingsrechthoeken vóór de overlaptest. Met margin=2 worden blobs waarvan de begrenzingsrechthoeken binnen 2 pixels van elkaar komen nog steeds samengevoegd; met margin=-2 worden alleen blobs samengevoegd waarvan de begrenzingsrechthoeken met ten minste 2 pixels overlappen. De natuurlijke afstemming: een positieve marge om blobs te verwerken die de drempelwaarde in aangrenzende stukken heeft opgebroken; een negatieve marge om dicht op elkaar gegroepeerde, afzonderlijke objecten gescheiden te houden.

merge_cb draait op elk kandidaatpaar voordat de samenvoeging plaatsvindt. De callback ontvangt de twee blobs en geeft True terug om de samenvoeging toe te staan of False om deze te voorkomen. Dit is het juiste hulpmiddel om samenvoegingen te controleren die de geometrische regel mist – bijvoorbeeld weigeren om twee blobs samen te voegen waarvan de rotation-hoeken meer dan een drempelwaarde verschillen, of weigeren om een kleine blob samen te voegen met een veel grotere als de kleine slechts spikkels is.

5.25.5. Projectiehistogrammen

x_hist_bins_max en y_hist_bins_max koppelen optionele projectiehistogrammen aan elke blob. Een projectiehistogram is het aantal geslaagde pixels langs één as: het X-as-histogram telt de geslaagde pixels per kolom binnen het begrenzingsvak van de blob op, en het Y-as-histogram telt per rij op. Beide hebben standaard de waarde nul – de histogrammen worden niet berekend tenzij een max die niet nul is wordt opgegeven, aangezien ze anders aan elke detectie werk zouden toevoegen.

Wanneer ze worden berekend, leveren de histogrammen een goedkoop 1D-signaal waarop een applicatie verdere analyse kan uitvoeren: het detecteren van de positie van een verticale streep binnen de blob, het vinden van het breekpunt van een tweekleurig doelwit, het tellen van hoeveel gaten er langs de lange as verschijnen. Ze worden gevuld als de eigenschappen x_hist_bins en y_hist_bins op elke Blob.

5.25.6. Extra geometrische hulpfuncties

Een handvol verdere geometrische maatstaven bestaat als functies op moduleniveau die een blob nemen en de gevraagde meting teruggeven:

  • image.get_solidity() geeft de soliditeit van de blob terug – pixels gedeeld door de oppervlakte van de convexe omhulling. Een massief gevuld gebied ligt dicht bij 1.0; een blob met holtes (een hoefijzer, een hand met gespreide vingers) zakt daar ruim onder.

  • image.get_convexity() geeft de convexiteit terug – de omtrek van de convexe omhulling gedeeld door de omtrek van de blob. Een perfect convexe blob is 1.0; gekartelde of ingekeepte blobs zijn lager.

  • image.get_major_axis_line() en image.get_minor_axis_line() geven Line-objecten terug langs de hoofd- en nevenassen van de blob, afgeleid van de geroteerde rechthoek met minimale oppervlakte.

  • image.get_enclosing_circle() geeft een Circle terug die de blob omsluit – nuttig wanneer een volgende fase een cirkel wil tekenen of ertegen wil testen.

  • image.get_enclosed_ellipse() geeft de 5-tuple (cx, cy, rx, ry, rotation) terug voor een ellips die is ingeschreven in de rechthoek met minimale oppervlakte van de blob. De waarden voeden rechtstreeks in draw_ellipse().

5.25.7. Een drempelwaarde automatisch aanleren

Een blob-detector is slechts zo goed als de drempelwaarden waarmee hij wordt uitgevoerd, en het werk van het vinden van de juiste drempelwaarde voor een doelkleur is een probleem op zich. Twee veelvoorkomende patronen verminderen dat werk.

Het eerste is interactieve selectie in de IDE: leg een frame vast, sleep een rechthoek rond een voorbeeld van de doelkleur, en laat de drempelwaarde-editor van de IDE de LAB-grenzen rapporteren die hij ziet. Die grenzen vallen in het script als de drempelwaarden van find_blobs() en de detector is klaar.

Het tweede is programmatisch automatisch aanleren: een kalibratieroutine die op de camera draait legt een frame vast, neemt een histogram van een bekende vlek waar het doelwit zich bevindt (get_histogram() met roi=), en leest het waardebereik van de vlek af van het histogram met get_percentile(). Het 5e percentiel stelt de ondergrens van elk kanaal in en het 95e de bovengrens, waarbij verdwaalde uitschieterpixels aan beide uiteinden worden genegeerd. Op een RGB565-afbeelding rapporteert één percentielaanroep alle drie de LAB-kanalen tegelijk, dus de twee aanroepen produceren de zes getallen die find_blobs() verwacht:

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)