5.23. Perspectiefcorrectie¶
Waarschuwing
De willekeurige 3-bij-3 transform-matrix wordt alleen ondersteund op de OpenMV Cam N6 – op elk ander board wordt het sleutelwoord stilzwijgend genegeerd. Applicaties die overal elders moeten draaien, moeten de kant-en-klare methode rotation_corr() gebruiken (met de corners=-vorm) of de gecorrigeerde afbeelding off-board vooraf berekenen.
De kant-en-klare methode rotation_corr() verpakt een bepaalde familie perspectiefvervormingen achter een kleine set parameters, en draait op elk ondersteund board. Sommige applicaties hebben een vervorming nodig die niet in die vorm past: een willekeurige projectieve hermapping van de ene vierhoek naar de andere, een gekalibreerde correctie voor een bekende montage die al off-line is uitgewerkt, een vervormingsmatrix die kant-en-klaar wordt aangeleverd door een voorafgaand algoritme. Voor die gevallen accepteert draw_image() – samen met copy(), crop() en scale() – een transform-sleutelwoord dat een handmatig opgebouwde 3-bij-3-matrix aanneemt die de vervorming rechtstreeks beschrijft.
5.23.1. Affiene en projectieve transformaties¶
Geometrische vervormingen worden uitgedrukt in homogene coördinaten: de pixelpositie (x, y) met een 1 toegevoegd, vermenigvuldigd met een 3-bij-3-matrix.
De affiene vorm is de plek om te beginnen. De onderste rij ligt vast op \((0, 0, 1)\):
Uitgeschreven is elke uitvoercoördinaat een lineaire combinatie van de invoercoördinaten plus een constante:
wat schaling, rotatie, scheeftrekking en translatie in elke combinatie dekt – en onder al deze blijven evenwijdige lijnen evenwijdig.
De projectieve (perspectief)vorm maakt de onderste rij vrij:
Uitgeschreven:
De deling door \(w' = g x + h y + 1\) is wat de transformatie projectief maakt in plaats van louter affien. Wanneer \(g\) en \(h\) beide nul zijn, blijft \(w'\) op één en doet de deling niets – opnieuw de affiene vorm. Wanneer een van beide niet nul is, varieert \(w'\) met de invoerpositie en worden pixels op verschillende posities met verschillende mate verkort, wat evenwijdige lijnen niet langer evenwijdig houdt – het is precies het keystone-effect van het bekijken van een plat vlak vanuit een schuine hoek. Een projectieve transformatie is de meest algemene geometrische vervorming die rechte lijnen naar rechte lijnen brengt; schalen, spiegelen, transponeren, roteren en de vierhoek-rotatiecorrectie zijn allemaal speciale gevallen ervan.
De benoemde transformaties volgen rechtstreeks uit de affiene vorm. De identiteitstransformatie is de identiteitsmatrix, en:
Voor de meeste handmatig opgebouwde transformaties begint een applicatie met een van deze als basis en vermenigvuldigt verdere matrices in voor elke aanvullende bewerking, eindigend met een enkele 3-bij-3-matrix die de samengestelde vervorming beschrijft. Matrices worden van rechts naar links toegepast: \(M = T R S\) voert eerst de schaling uit, dan de rotatie, dan de translatie. De samenstelling die uiteindelijk iedereen nodig heeft, is rotatie rond het midden van de afbeelding – een kale rotatiematrix draait de afbeelding rond de pixeloorsprong in de linkerbovenhoek, dus de gecentreerde versie verplaatst het midden \((c_x, c_y)\) naar de oorsprong, roteert, en verplaatst het terug:
5.23.2. Het transform-sleutelwoord¶
De matrix wordt doorgegeven via een transform-sleutelwoord, aangeleverd als een 3-bij-3 ulab.numpy.ndarray. De methode om naar te grijpen is draw_image(), die de bron via de matrix vervormt terwijl ze die op een bestemming tekent – het resultaat belandt in een buffer die de applicatie beheert, en de vervorming wordt samengesteld met al het andere in de aanroep: de schaling, de alpha-blending, het maskeren.
import ulab.numpy as np
M = np.array([[1.2, 0.0, -20.0],
[0.0, 1.2, -15.0],
[0.0, 0.0, 1.0]])
canvas.draw_image(img, transform=M)
Het voorbeeld vervormt img op canvas met een schaal van 1,2 in elke richting en respectievelijk 20 en 15 pixels naar links en omhoog verschoven – een affiene vervorming die rechtstreeks is opgebouwd uit de hierboven beschreven matrixwaarden. Hetzelfde sleutelwoord op copy(), crop() en scale() past de vervorming toe op de afbeelding zelf.