5.31. Förskjutningsmatchning

Mallmatchning svarar på var finns denna delbild i bildrutan; likhetspoängsättning svarar på hur lika är dessa två bilder totalt sett. En annan fråga sitter mellan dem: de två bildrutorna visar samma scen, men kameran (eller scenen) rörde sig mellan dem – med hur mycket? Det är förskjutnings-problemet, och image-modulen löser det med en enda faskorrelationsmetod.

5.31.1. Faskorrelationsförskjutning

find_displacement() uppskattar den stela inriktningen mellan två lika stora bilder med hjälp av faskorrelation – en frekvensdomänsmetod som kör en snabb Fouriertransform (FFT) på varje bild, korskorrelerar deras faser och lokaliserar toppen i resultatet. Toppositionen är den translation som inriktar de två bilderna:

d = img.find_displacement(template)

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

Den returnerade Displacement bär x_translation och y_translation – pixelförskjutningen i varje axel – plus response, ett konfidensvärde från 0.0 till 1.0 där 1.0 är en perfekt topp. Att filtrera bort detekteringar under response > 0.3 förkastar falska resultat där faskorrelationen aldrig hittade en ren topp.

Både rotation och scale är 0.0 respektive 1.0 i standardläget; de antar reella värden endast när logpolar=True (se nedan).

Metoden bär två praktiska begränsningar. Den första är tvåpotensdimensioner: FFT:n i hjärtat av faskorrelationen är snabbast – och på kameran endast fullt stödd – vid storlekar som 32-gånger-32, 64-gånger-64 och 128-gånger-128. Den renaste konfigurationen är att fånga direkt vid en av dessa storlekar, genom att skicka upplösningen till framesize() som en tupel:

csi0.framesize((64, 64))

En tillämpning som behöver förskjutning från en större bildruta beskär istället en tvåpotens-delbild ur det område den bryr sig om och kör matcharen på den.

Den andra är lika stora indata: roi och template_roi måste välja identiska bredder och höjder, annars vägrar matcharen anropet. Två infångningar från samma kamera med samma konfiguration uppfyller detta automatiskt; en infångad bildruta jämförd mot en inläst referens behöver båda beskurna till matchande tvåpotens-delbilder först.

5.31.2. Rotation och skala via log-polär

Standardläget hittar endast translation. När de två bildrutorna även skiljer sig i rotation kring ett valt centrum eller i skala kring samma centrum, omvandlar körning av faskorrelationen på den log-polära omprojektionen av varje bild dessa parametrar till translation i det log-polära koordinatsystemet – vilket samma faskorrelationsmatchare kan återställa:

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

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

Med logpolar=True kör metoden samma matchningspipeline mot de log-polärt projicerade bilderna istället för originalen. Fälten rotation och scale i resultatet kommer tillbaka ifyllda: rotation är vinkeln i radianer mellan de två bildrutorna, scale är skalfaktorn mellan dem. x_translation och y_translation blir meningslösa i detta läge (translationen längs de log-polära axlarna motsvarar inte en linjär translation i källan).

Nyckelordet fix_rotation_scale=True täcker mellanfallet: de två bilderna skiljer sig i både translation och rotation/skala, och tillämpningen behöver endast translation efter att ha korrigerat för rotationen och skalan. Matcharen kör den log-polära passningen först för att återställa rotationen och skalan, tillämpar inversen på en av bilderna, och kör sedan translationspassningen för att återställa den återstående förskjutningen. Flaggan är meningsfull endast när logpolar=False – den ber translationslägesmatcharen att först ta bort rotationen/skalan.

Mönstret från Polära transformer – kartesisk → polär → matcha – är vad find_displacement() med logpolar=True gör i ett anrop. Tillämpningen lagrar en log-polär referensdelbild vid uppstart, fångar och log-polärt transformerar varje livebildruta, och metoden återställer rotations- och skalskillnaden mellan dem. För tillämpningar som behöver en rotations- och skalinvariant spårare – en dockningsrobot vars kamera lutar och zoomar när den närmar sig ett mål, ett stabiliserat gimbal som behöver veta hur bilden roterar relativt en referens – är detta standardkonstruktionen.

5.31.3. Den klassiska användningen

Den vanligaste användningen av find_displacement() är rörelseuppskattning bildruta-till-bildruta i en pipeline som bearbetar en kamera i rörelse. Kameran fångar en liten tvåpotens-delbild vid bildruta N, fångar den lika stora delbilden vid bildruta N+1, kör find_displacement() på de två, och läser av pixelförskjutningen mellan dem. Förskjutningen är den uppskattade rörelsen hos kameran (eller hos scenen, beroende på vems referensram som spelar roll) mellan de två infångningarna, användbar för:

  • Optiskt-flöde-liknande avkänning – en svävande drönare med en nedåtriktad kamera använder förskjutningen per bildruta för att uppskatta sin laterala rörelse och mata tillbaka den till flygkontrollern.

  • Bildstabilisering – förskjutningen mellan på varandra följande bildrutor subtraheras bort från den infångade bilden innan den spelas in eller överförs, vilket ger en jämnare videoström.

  • Inspektionsinriktning – en skannande kamera som rör sig längs ett transportband använder förskjutningen per bildruta för att registrera varje bildruta mot nästa och bygga en hopfogad vy av hela detaljen.

Var och en av dessa tillämpningar tar samma form: fånga, förskjut, ackumulera till en löpande uppskattning, fånga igen.