5.31. Verplaatsingsovereenkomst

Template matching beantwoordt waar deze patch zich binnen het frame bevindt; gelijkenisscore beantwoordt hoe sterk deze twee afbeeldingen in het geheel op elkaar lijken. Een andere vraag ligt daartussen: de twee frames tonen dezelfde scène, maar de camera (of de scène) is ertussen verplaatst – met hoeveel? Dat is het verplaatsingsprobleem, en de image-module lost het op met één enkele fasecorrelatiemethode.

5.31.1. Verplaatsing via fasecorrelatie

find_displacement() schat de starre uitlijning tussen twee afbeeldingen van gelijke grootte met behulp van fasecorrelatie – een frequentiedomeinmethode die een snelle Fouriertransformatie (FFT) op elke afbeelding uitvoert, hun fasen kruiscorreleert en de piek in het resultaat lokaliseert. De piekpositie is de translatie die de twee afbeeldingen uitlijnt:

d = img.find_displacement(template)

print("shift:", d.x_translation, d.y_translation,
      " response:", d.response)

De geretourneerde Displacement draagt x_translation en y_translation – de pixelverschuiving in elke as – plus response, een betrouwbaarheidsscore van 0.0 tot 1.0 waarbij 1.0 een perfecte piek is. Het uitfilteren van detecties onder response > 0.3 verwerpt valse resultaten waarin de fasecorrelatie nooit een schone piek vond.

Zowel rotation als scale zijn respectievelijk 0.0 en 1.0 in de standaardmodus; ze nemen alleen echte waarden aan wanneer logpolar=True (zie hieronder).

De methode brengt twee praktische beperkingen met zich mee. De eerste is afmetingen die een macht van twee zijn: de FFT in de kern van fasecorrelatie is het snelst – en op de camera alleen volledig ondersteund – bij afmetingen als 32-bij-32, 64-bij-64 en 128-bij-128. De schoonste opzet is om direct op een van die afmetingen vast te leggen, door de resolutie als een tuple door te geven aan framesize():

csi0.framesize((64, 64))

Een toepassing die verplaatsing van een groter frame nodig heeft, snijdt in plaats daarvan een patch ter grootte van een macht van twee uit het gebied waar het om geeft en draait de matcher daarop.

De tweede is invoer van gelijke grootte: roi en template_roi moeten identieke breedtes en hoogtes selecteren, anders weigert de matcher de aanroep. Twee opnamen van dezelfde camera bij dezelfde configuratie voldoen hier automatisch aan; een vastgelegd frame vergeleken met een geladen referentie vereist dat beide eerst tot overeenkomende patches met een macht van twee worden uitgesneden.

5.31.2. Rotatie en schaal via log-polair

De standaardmodus vindt alleen translatie. Wanneer de twee frames ook verschillen in rotatie om een gekozen middelpunt of in schaal om hetzelfde middelpunt, zet het uitvoeren van de fasecorrelatie op de log-polaire herprojectie van elke afbeelding die parameters om in translatie in het log-polaire coördinatenstelsel – die dezelfde fasecorrelatie-matcher kan herstellen:

d = img.find_displacement(template, logpolar=True)

print("rotation rad:", d.rotation,
      " scale:", d.scale,
      " response:", d.response)

Met logpolar=True draait de methode dezelfde matchingpijplijn tegen de log-polair geprojecteerde afbeeldingen in plaats van de originelen. De velden rotation en scale van het resultaat komen ingevuld terug: rotation is de hoek in radialen tussen de twee frames, scale is de schaalfactor tussen hen. x_translation en y_translation worden in deze modus betekenisloos (de translatie langs de log-polaire assen komt niet overeen met een lineaire translatie in de bron).

Het trefwoord fix_rotation_scale=True dekt het tussenliggende geval: de twee afbeeldingen verschillen in zowel translatie als rotatie/schaal, en de toepassing heeft alleen translatie nodig na correctie voor de rotatie en schaal. De matcher draait eerst de log-polaire pas om de rotatie en schaal te herstellen, past het omgekeerde toe op een van de afbeeldingen, en draait dan de translatiepas om de resterende verschuiving te herstellen. De vlag is alleen zinvol wanneer logpolar=False – hij vraagt de matcher in translatiemodus om eerst de rotatie/schaal te verwijderen.

Het patroon van Polaire transformaties – Cartesisch → polair → match – is wat find_displacement() met logpolar=True in één aanroep doet. De toepassing slaat bij het opstarten een referentie-log-polaire patch op, legt elk live frame vast en transformeert het naar log-polair, en de methode herstelt het rotatie-en-schaalverschil tussen hen. Voor toepassingen die een rotatie- en schaal-invariante tracker nodig hebben – een aanmerende robot wiens camera kantelt en inzoomt terwijl hij een doel nadert, een gestabiliseerde gimbal die moet weten hoe de afbeelding roteert ten opzichte van een referentie – is dit de standaardconstructie.

5.31.3. Het klassieke gebruik

Het meest voorkomende gebruik van find_displacement() is frame-naar-frame-bewegingsschatting in een pijplijn die een bewegende camera verwerkt. De cam legt een kleine patch met een macht van 2 vast op frame N, legt de patch van gelijke grootte vast op frame N+1, draait find_displacement() op de twee, en leest de pixelverschuiving daartussen af. De verschuiving is de geschatte beweging van de camera (of van de scène, afhankelijk van wiens referentiekader van belang is) tussen de twee opnamen, nuttig voor:

  • Optical-flow-achtige waarneming – een zwevende drone met een naar beneden gerichte camera gebruikt de verplaatsing per frame om zijn laterale beweging te schatten en die terug te koppelen naar de vluchtcontroller.

  • Beeldstabilisatie – de verplaatsing tussen opeenvolgende frames wordt uit de vastgelegde afbeelding afgetrokken voordat deze wordt opgenomen of verzonden, wat een vloeiendere videostroom oplevert.

  • Inspectie-uitlijning – een scannende cam die langs een lopende band beweegt gebruikt de verplaatsing per frame om elk frame ten opzichte van het volgende te registreren en een aaneengeregen beeld van het hele onderdeel op te bouwen.

Elk van die toepassingen neemt dezelfde vorm aan: vastleggen, verplaatsen, accumuleren in een lopende schatting, opnieuw vastleggen.