Cet article utilise Python et OpenCV pour une transformation de perspective : déplacer les quatre coins d’une image vers quatre nouveaux. En résumé, getPerspectiveTransform calcule la matrice et warpPerspective déforme les pixels. L’exemple est une grille 600×600 avec une silhouette. (Les libellés des figures sont en anglais.)

Points clés
| Regarder | Idée |
|---|---|
| Ce que l’on fait | Fixer où vont les quatre coins, et le plan s’étire en trapèze |
| Code et résultat | Exécuter le script ci-dessous avec la même arborescence que la figure |
| Dossiers | Placer source_pics et save_pics à côté du script |
| Coordonnées | Le haut gauche est [0, 0]. Ordre : haut-gauche → bas-gauche → bas-droit → haut-droit |
| Le reste des lignes | Lecture, taille, matrice, déformation, enregistrement |
| Taille de sortie | Les pixels hors du troisième argument sont coupés |
| Votre propre image | Ne changer que l’ordre des points et la taille de sortie vers le rectangle voulu |
| Caméra contrainte | Même en biais, apparier les quatre coins du plan réel donne encore un rectangle de données |
Une transformation de perspective fixe où vont les quatre coins
Une transformée affine (warpAffine) laisse les parallèles parallèles. Une de perspective (getPerspectiveTransform et warpPerspective) peut bouger les quatre coins séparément, donc un trapèze large devant et étroit derrière. Remettre une carte de visite en rectangle vue de dessus, ou regarder un sol en plan, relèvent de ces fonctions.
Passez les coins d’entrée et les coins de sortie dans le même ordre. Cet article ne suit pas l’algèbre de la matrice. Si vous savez où vont les quatre coins, vous pouvez utiliser les fonctions.
Le script et l’avant/après
D’abord un script qui tourne. Les sections suivantes suivent les coordonnées et le reste des lignes.
import numpy as np
import cv2
image = cv2.imread("source_pics/test_1.png", cv2.IMREAD_COLOR)
height, width, channels = image.shape[:3]
source_points = np.array([[0, 0], [0, height], [width, height], [width, 0]], dtype=np.float32)
target_points = np.array([[200, 0], [0, 600], [600, 600], [400, 0]], dtype=np.float32)
mat = cv2.getPerspectiveTransform(source_points, target_points)
perspective_image = cv2.warpPerspective(image, mat, (width, height))
cv2.imwrite("save_pics/perspective_image.png", perspective_image)

Cet exemple rapproche le bord supérieur, donc le résultat est un trapèze étroit en haut et large en bas. La marge noire est la partie du canevas de sortie hors du quadrilatère déformé.
Placer les dossiers à côté du script

Les chemins du code sont relatifs au test_1.py que vous lancez. L’image lue est source_pics/test_1.png ; le fichier écrit est save_pics/perspective_image.png. Pour vos fichiers, alignez ces noms ou changez les chaînes de chemin.
Si imread échoue, image vaut None et la ligne suivante, image.shape, s’arrête. Avant de lancer, vérifiez l’orthographe des dossiers et le répertoire de travail courant.
Les coordonnées commencent à [0, 0] en haut à gauche
source_points = np.array([[0, 0], [0, height], [width, height], [width, 0]], dtype=np.float32)
target_points = np.array([[200, 0], [0, 600], [600, 600], [400, 0]], dtype=np.float32)
Les tableaux suivent cet ordre. L’origine n’est pas en bas, comme sur du papier millimétré.
| Ordre | source_points | target_points |
|---|---|---|
| Haut gauche | [0, 0] | [200, 0] |
| Bas gauche | [0, height] | [0, 600] |
| Bas droit | [width, height] | [600, 600] |
| Haut droit | [width, 0] | [400, 0] |
Cet exemple fait 600×600, donc height et width valent 600. Remplis, les tableaux ressemblent à ceci.
source_points = np.array([[0, 0], [0, 600], [600, 600], [600, 0]], dtype=np.float32)
target_points = np.array([[200, 0], [0, 600], [600, 600], [400, 0]], dtype=np.float32)
![Carte des quatre coins pour une transformation de perspective, d’après source_points et target_points. Avec origine en haut à gauche, rapprocher le bord supérieur raccourcit le haut. [0, 0] et [600, 0] vont vers [200, 0] et [400, 0].](https://toolcluster.app/wp-content/uploads/2026/08/opencv-perspective-coords.png)
Les deux points du haut se rapprochent, donc le bord supérieur raccourcit. Les deux du bas ne bougent pas. Changez les nombres et le même appariement des quatre coins fait un autre trapèze.
Si l’ordre d’entrée et l’ordre de sortie ne correspondent pas, la correspondance se tord. Écrivez les deux en haut-gauche → bas-gauche → bas-droit → haut-droit. Si vous prenez les points sur un axe y mathématique (le haut est positif), l’image paraît à l’envers.
Ce que font les autres lignes
Imports
import numpy as np
import cv2
NumPy tient les tableaux de points. Le cv2 d’OpenCV lit, écrit et déforme les images.
Lecture de l’image
image = cv2.imread("source_pics/test_1.png", cv2.IMREAD_COLOR)
cv2.imread charge test_1.png depuis source_pics, à côté du script, en couleur, dans image.
Taille de l’image
height, width, channels = image.shape[:3]
shape donne la hauteur, la largeur et le nombre de canaux. Cet exemple n’utilise pas les canaux, mais le nombre de valeurs dépaquetées doit correspondre, donc on prend les trois.
Alignez le nombre de variables sur le nombre de valeurs que vous dépaquetez.
Points pour la matrice
source_points = np.array([[0, 0], [0, height], [width, height], [width, 0]], dtype=np.float32)
target_points = np.array([[200, 0], [0, 600], [600, 600], [400, 0]], dtype=np.float32)
Quatre points XY de chaque côté. Sur cette image source, [height, width] vaut [600, 600], donc les tableaux contiennent :
source_points = [[ 0. 0.]
[ 0. 600.]
[600. 600.]
[600. 0.]]
target_points = [[200. 0.]
[ 0. 600.]
[600. 600.]
[400. 0.]]
Ce sont les coordonnées de la figure. La déformation utilise cet appariement.
La matrice de transformation
mat = cv2.getPerspectiveTransform(source_points, target_points)
cv2.getPerspectiveTransform calcule la matrice à partir des quatre coins d’entrée et des quatre de sortie. Dans cet exemple, les valeurs sont :
mat = [[ 3.33333333e-01 -3.33333333e-01 2.00000000e+02]
[ 0.00000000e+00 3.33333333e-01 0.00000000e+00]
[ 0.00000000e+00 -1.11111111e-03 1.00000000e+00]]
Le sens de chaque coefficient n’est pas utile ici. Si les coins vont où vous vouliez, passez la valeur de retour à la ligne suivante.
La déformation
perspective_image = cv2.warpPerspective(image, mat, (width, height))
cv2.warpPerspective prend l’image source, la matrice, et la largeur et la hauteur de sortie. Cet exemple ne raccourcit qu’un bord, donc la taille de sortie reste (width, height), comme la source. Choisissez la vraie taille en regardant les coordonnées transformées.
Enregistrement
cv2.imwrite("save_pics/perspective_image.png", perspective_image)
cv2.imwrite écrit perspective_image.png dans save_pics, à côté du script. Créez d’abord le dossier ; l’écriture échoue s’il manque.
Si la sortie est trop petite, le débordement est coupé
Gardez la sortie à 600×600 et prenez des points comme ceux-ci : le haut élargi sort du canevas.
source_points = np.array([[200, 0], [0, 600], [600, 600], [400, 0]], dtype=np.float32)
target_points = np.array([[0, 0], [0, 600], [600, 600], [600, 0]], dtype=np.float32)
![Coupe quand le canevas de sortie est trop petit, d’après des points hors du cadre. Explique que le troisième argument de warpPerspective est la taille écrite. Les [0, 0] et [600, 0] d’origine sont hors de 600×600, donc le haut est coupé.](https://toolcluster.app/wp-content/uploads/2026/08/opencv-perspective-output-crop-en.png)
Le troisième argument est la taille de l’image que vous écrivez, pas la taille du monde déformé. Les pixels dont les points sortent de ce rectangle disparaissent. Pour les garder, agrandissez d’abord la sortie, ou choisissez des points target qui tiennent tous dedans.
Si un x ou un y de target dépasse la largeur ou la hauteur de sortie, et que vous laissez le troisième argument à la taille source, ça coupe. Quand ça a l’air coupé, comparez d’abord les points à la taille de sortie.
Les mêmes étapes marchent sur vos propres photos
Gardez l’ordre des quatre coins et les deux mêmes fonctions marchent sur des photos qui ne sont pas une grille. Ne changez que les nombres de target et la taille de sortie vers le rectangle voulu.
Même si la caméra est en biais, apparier quatre coins donne encore un rectangle
Vous avez fait une chaîne courte : apparier les coins d’entrée aux coins de sortie, résoudre la matrice, écrire sur le canevas de sortie. Les fonctions sont les mêmes sur la grille et sur une photo du sol. Sur site, seuls le choix des points et la taille de sortie changent.
Quand la position de la caméra est fixée par la machine
Sur un équipement ou un banc d’inspection, on ne peut souvent pas poser la caméra pile au-dessus de la pièce. Capots, tuyaux, protecteurs et zone robot se décident d’abord ; l’objectif se glisse après. Mesurer ou lire cette image telle quelle laisse un trapèze large devant et étroit derrière, donc longueurs et positions sont faussées.
Appariez les quatre coins et vous récupérez le rectangle du plan voulu, sans reconstruire le bâti. La collecte de données reste possible quand la pose de la caméra est contrainte par la structure. L’astuce réelle est de poser les points sur les quatre coins du plan physique, pas les quatre coins de l’écran. Un coin de pièce, un trou de montage, un joint de sol — tout point que vous pourrez re-désigner plus tard — et les étapes de cet article s’appliquent telles quelles.
Vous n’avez pas à écrire les maths vous-même
OpenCV est une implémentation pour ce travail. Ranger les points avec NumPy et les passer à getPerspectiveTransform et warpPerspective d’OpenCV, c’est choisir une implémentation maintenue plutôt que d’écrire l’algèbre soi-même. Ce choix n’est pas limité à OpenCV. Autour du traitement d’image, du calcul numérique, des communications et de la commande, le même travail a déjà des implémentations, tenues et versionnées par d’autres. Lire et utiliser ce code vous ramène plus vite aux contraintes de la machine que dériver les maths projectives depuis zéro.
S’en servir suffit. Si vous tombez sur un trou ou quelque chose d’obscur, vous pouvez signaler, corriger la doc ou envoyer un patch. La quantité rendue varie. Même zéro vous met encore du côté qui fait durer ce travail, en attendant la version suivante. Adaptez l’outil à votre machine, et rendez un peu si besoin. Cette boucle dépense mieux le temps d’ingénierie que de porter une réécriture interne complète.
Même avec une caméra en biais, quatre coins font encore un rectangle de données. Ensuite, le vrai travail est de mesurer, lire et garder ce qui est sur ce rectangle.

Laisser un commentaire