Este artículo usa Python y OpenCV para una transformación de perspectiva: pasar las cuatro esquinas de una imagen a otras cuatro. En síntesis, getPerspectiveTransform calcula la matriz y warpPerspective deforma los píxeles. El ejemplo es una cuadrícula 600×600 con una silueta. (Las etiquetas de las figuras están en inglés.)

Puntos clave
| Mira esto | Idea |
|---|---|
| Qué estamos haciendo | Fijas a dónde van las cuatro esquinas y el plano se estira en trapecio |
| Código y resultado | Ejecuta el script de abajo con la misma carpeta que la figura |
| Carpetas | Pon source_pics y save_pics junto al script |
| Coordenadas | Arriba a la izquierda es [0, 0]. El orden es arriba-izq. → abajo-izq. → abajo-der. → arriba-der. |
| El resto de líneas | Lectura, tamaño, matriz, deformación, guardado |
| Tamaño de salida | Los píxeles fuera del tercer argumento se recortan |
| Tu propia imagen | Cambia solo el orden de los puntos y el tamaño de salida al rectángulo que quieres |
| Cámara limitada | Aunque esté en ángulo, emparejar las cuatro esquinas del plano real sigue dando un rectángulo de datos |
Una transformación de perspectiva fija a dónde van las cuatro esquinas
Una transformada afín (warpAffine) deja las paralelas paralelas. Una de perspectiva (getPerspectiveTransform y warpPerspective) mueve las cuatro esquinas por separado, así que puedes hacer un trapecio ancho delante y estrecho detrás. Poner una tarjeta de visita en un rectángulo visto desde arriba, o mirar un suelo en planta, son usos de estas funciones.
Pasa las esquinas de entrada y las de salida en el mismo orden. Este artículo no sigue el álgebra de la matriz. Si sabes a dónde van las cuatro esquinas, puedes usar las funciones.
El script y el antes/después
Primero un script que funciona. Las secciones siguientes siguen las coordenadas y el resto de líneas.
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)

Este ejemplo acerca el borde superior, así que el resultado es un trapecio estrecho arriba y ancho abajo. El margen negro es la parte del lienzo de salida que queda fuera del cuadrilátero deformado.
Pon las carpetas junto al script

Las rutas del código son relativas al test_1.py que ejecutas. La imagen que lees es source_pics/test_1.png; el archivo que escribes es save_pics/perspective_image.png. Con tus archivos, iguala esos nombres o cambia las cadenas de ruta.
Si imread falla, image es None y la línea siguiente, image.shape, se detiene. Antes de ejecutar, revisa la ortografía de las carpetas y el directorio de trabajo actual.
Las coordenadas empiezan en [0, 0] arriba a la izquierda
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)
Los arrays van en este orden. El origen no está abajo, como en un papel milimetrado.
| Orden | source_points | target_points |
|---|---|---|
| Arriba izquierda | [0, 0] | [200, 0] |
| Abajo izquierda | [0, height] | [0, 600] |
| Abajo derecha | [width, height] | [600, 600] |
| Arriba derecha | [width, 0] | [400, 0] |
Este ejemplo es 600×600, así que height y width valen 600. Con números, los arrays quedan así.
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)
![Mapa de cuatro esquinas para una transformación de perspectiva, según source_points y target_points. Con origen arriba a la izquierda, acercar el borde superior acorta la parte de arriba. [0, 0] y [600, 0] pasan a [200, 0] y [400, 0].](https://toolcluster.app/wp-content/uploads/2026/08/opencv-perspective-coords.png)
Los dos puntos de arriba se acercan, así que el borde superior se acorta. Los dos de abajo no se mueven. Cambia los números y el mismo emparejado de cuatro esquinas hace otro trapecio.
Si el orden de entrada y el de salida no coinciden, la correspondencia se tuerce. Escribe ambos como arriba-izq. → abajo-izq. → abajo-der. → arriba-der. Si tomas puntos en un eje y matemático (arriba es positivo), la imagen se ve al revés.
Qué hace el resto de líneas
Importaciones
import numpy as np
import cv2
NumPy guarda los arrays de puntos. El cv2 de OpenCV lee, escribe y deforma imágenes.
Lectura de la imagen
image = cv2.imread("source_pics/test_1.png", cv2.IMREAD_COLOR)
cv2.imread carga test_1.png desde source_pics, junto al script, en color, en image.
Tamaño de la imagen
height, width, channels = image.shape[:3]
shape da altura, ancho y número de canales. Este ejemplo no usa los canales, pero la cantidad de valores que desempaquetas tiene que coincidir, así que se toman los tres.
Iguala el número de variables al número de valores que desempaquetas.
Puntos para la matriz
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)
Cuatro puntos XY en cada array. En esta imagen de origen [height, width] es [600, 600], así que los arrays contienen:
source_points = [[ 0. 0.]
[ 0. 600.]
[600. 600.]
[600. 0.]]
target_points = [[200. 0.]
[ 0. 600.]
[600. 600.]
[400. 0.]]
Esas son las coordenadas de la figura. La deformación usa ese emparejado.
La matriz de transformación
mat = cv2.getPerspectiveTransform(source_points, target_points)
cv2.getPerspectiveTransform calcula la matriz a partir de las cuatro esquinas de entrada y las cuatro de salida. En este ejemplo los valores son:
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]]
Aquí no hace falta el significado de cada entrada. Si las esquinas van donde querías, pasa el valor de retorno a la línea siguiente.
La deformación
perspective_image = cv2.warpPerspective(image, mat, (width, height))
cv2.warpPerspective toma la imagen de origen, la matriz y el ancho y alto de salida. Este ejemplo solo acorta un borde, así que el tamaño de salida sigue en (width, height), igual que el origen. Elige el tamaño real mirando las coordenadas transformadas.
Guardado
cv2.imwrite("save_pics/perspective_image.png", perspective_image)
cv2.imwrite escribe perspective_image.png en save_pics, junto al script. Crea la carpeta antes; si falta, la escritura falla.
Si la salida es demasiado pequeña, el excedente se recorta
Deja la salida en 600×600 y toma puntos como estos, y la parte superior ensanchada se sale del lienzo.
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)
![Recorte si el lienzo de salida es demasiado pequeño, según puntos que salen del marco. Explica que el tercer argumento de warpPerspective es el tamaño escrito. El [0, 0] y [600, 0] originales quedan fuera de 600×600; se corta arriba.](https://toolcluster.app/wp-content/uploads/2026/08/opencv-perspective-output-crop-en.png)
El tercer argumento es el tamaño de la imagen que escribes, no el tamaño del mundo deformado. Los píxeles cuyos puntos quedan fuera de ese rectángulo desaparecen. Para conservarlos, agranda primero la salida, o elige puntos target que quepan todos.
Si un x o y de target pasa el ancho o el alto de salida, y dejas el tercer argumento en el tamaño de origen, se recorta. Cuando parece cortado, compara primero los puntos con el tamaño de salida.
Los mismos pasos valen para tus propias fotos
Mantén el orden de las cuatro esquinas y las mismas dos funciones sirven en fotos que no son una cuadrícula. Cambia solo los números de target y el tamaño de salida al rectángulo que quieres.
Aunque la cámara esté en ángulo, emparejar cuatro esquinas sigue dando un rectángulo
Lo que hiciste es una cadena corta: emparejar las esquinas de entrada con las de salida, resolver la matriz y escribir en el lienzo de salida. Las funciones son las mismas en la cuadrícula y en una foto del suelo. En la instalación, solo cambian cómo tomas los puntos y el tamaño de salida.
Cuando la posición de la cámara la fija la máquina
En equipos y bancos de inspección a menudo no puedes poner la cámara justo encima de la pieza. Cubiertas, tuberías, resguardos y el alcance del robot se deciden antes; la lente se encaja después. Si mides o lees esa imagen tal cual, sigues teniendo un trapecio ancho delante y estrecho detrás, así que longitudes y posiciones salen sesgadas.
Empareja las cuatro esquinas y recuperas el rectángulo del plano que quieres, sin reconstruir el bastidor. La recogida de datos sigue siendo posible cuando la pose de la cámara está limitada por la estructura. El truco de verdad es poner los puntos en las cuatro esquinas del plano físico, no en las cuatro del monitor. Una esquina de pieza, un agujero de utillaje, una junta del suelo — cualquier punto que puedas señalar otra vez después — y los pasos de este artículo valen tal cual.
No hace falta escribir las matemáticas tú
OpenCV es una implementación para ese trabajo. Ordenar los puntos con NumPy y pasarlos a getPerspectiveTransform y warpPerspective de OpenCV es elegir una implementación mantenida en vez de escribir el álgebra tú. Esa elección no se limita a OpenCV. En torno al procesado de imagen, el cálculo numérico, las comunicaciones y el control, el mismo trabajo ya tiene implementaciones, y hay quien las mantiene y sube de versión. Leer y usar ese código te devuelve antes a las limitaciones de la máquina que derivar las matemáticas proyectivas desde cero.
Usarlo basta. Si das con un agujero o algo poco claro, puedes reportarlo, arreglar la documentación o enviar un parche. Cuánto devuelves varía. Aunque sea cero, esperar la siguiente versión ya te pone del lado que mantiene ese trabajo. Ajusta la herramienta a tu máquina y, si hace falta, devuelve un poco. Ese bucle gasta mejor el tiempo de ingeniería que cargar con una reescritura interna completa.
Aunque la cámara esté en ángulo, cuatro esquinas siguen haciendo un rectángulo de datos. Después, el trabajo de verdad es medir, leer y guardar lo que hay en ese rectángulo.

Deja una respuesta