5.23. Correction de perspective¶
Avertissement
La matrice transform 3 par 3 arbitraire n’est prise en charge que sur l’OpenMV Cam N6 – le mot-clé est ignoré silencieusement sur toutes les autres cartes. Les applications qui doivent fonctionner ailleurs doivent utiliser la méthode prête à l’emploi rotation_corr() (avec sa forme corners=) ou pré-calculer l’image corrigée en dehors de la carte.
La méthode prête à l’emploi rotation_corr() regroupe une famille particulière de déformations de perspective derrière un petit ensemble de paramètres, et fonctionne sur toutes les cartes prises en charge. Certaines applications nécessitent une déformation qui ne correspond pas à cette forme : un remappage projectif arbitraire d’un quadrilatère vers un autre, une correction calibrée pour un montage connu déjà déterminée hors ligne, une matrice de déformation fournie toute faite par un algorithme amont. Pour ces cas, draw_image() – ainsi que copy(), crop() et scale() – accepte un mot-clé transform qui prend une matrice 3 par 3 construite à la main décrivant directement la déformation.
5.23.1. Transformations affines et projectives¶
Les déformations géométriques s’expriment en coordonnées homogènes : la position de pixel (x, y) à laquelle on ajoute un 1, multipliée par une matrice 3 par 3.
La forme affine est le point de départ. Sa ligne du bas est fixée à \((0, 0, 1)\) :
Développée, chaque coordonnée de sortie est une combinaison linéaire des coordonnées d’entrée plus une constante :
ce qui couvre la mise à l’échelle, la rotation, le cisaillement et la translation dans n’importe quelle combinaison – et sous toutes ces opérations, les droites parallèles restent parallèles.
La forme projective (perspective) libère la ligne du bas :
Développée :
La division par \(w' = g x + h y + 1\) est ce qui rend la transformation projective plutôt que simplement affine. Lorsque \(g\) et \(h\) sont tous deux nuls, \(w'\) reste égal à un et la division n’a aucun effet – on retrouve la forme affine. Lorsque l’un ou l’autre est non nul, \(w'\) varie avec la position d’entrée et les pixels situés à différentes positions sont raccourcis de différentes quantités, ce qui ne maintient plus les droites parallèles parallèles – c’est exactement l’effet de trapèze que l’on obtient en regardant un plan plat sous un angle oblique. Une transformation projective est la déformation géométrique la plus générale qui transforme les droites en droites ; la mise à l’échelle, le retournement, la transposition, la rotation et la correction de rotation à quatre coins en sont tous des cas particuliers.
Les transformations nommées découlent directement de la forme affine. La transformation identité est la matrice identité, et :
Pour la plupart des transformations construites à la main, une application part de l’une de ces matrices comme base et y multiplie d’autres matrices pour chaque opération supplémentaire, aboutissant à une seule matrice 3 par 3 qui décrit la déformation composite. Les matrices s’appliquent de droite à gauche : \(M = T R S\) exécute d’abord la mise à l’échelle, puis la rotation, puis la translation. La composition dont tout le monde a besoin tôt ou tard est la rotation autour du centre de l’image – une matrice de rotation seule fait tourner l’image autour de l’origine des pixels située dans le coin supérieur gauche, donc la version centrée déplace le centre \((c_x, c_y)\) vers l’origine, effectue la rotation, puis le replace :
5.23.2. Le mot-clé transform¶
La matrice est fournie via un mot-clé transform, sous la forme d’un ulab.numpy.ndarray 3 par 3. La méthode à privilégier est draw_image(), qui déforme la source à travers la matrice tout en la dessinant sur une destination – le résultat se retrouve dans un tampon que l’application contrôle, et la déformation se compose avec tout le reste de l’appel : la mise à l’échelle, le mélange alpha, le masquage.
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)
L’exemple déforme img sur canvas en le mettant à l’échelle de 1,2 dans chaque direction et en le décalant respectivement de 20 et 15 pixels vers la gauche et vers le haut – une déformation affine construite directement à partir des entrées de la matrice décrites ci-dessus. Le même mot-clé sur copy(), crop() et scale() applique la déformation à l’image elle-même.