?️ Como trasladar, rotar, escalar y recortar una imagen | Python – OpenCV
En este post veremos algunas transformaciones geométricas a una imagen, tales como: traslación, rotación, escalado y recorte. Para ello usaremos como siempre el lenguaje de programación Python en su versión 3, mientras que para OpenCV estaremos usando 4.2.0, pero de igual manera servirá para otras versiones.
CONTENIDO:
- Trasladando una imagen
- Rotando una imagen
- Escalando una imagen
- Recortando una imagen
Para la realización de este post estaremos usando la siguiente imagen:
Trasladando una imagen
Aplicar traslación a una imagen quiere decir que esta cambiará de ubicación, realizando desplazamiento en el eje x, y o ambos.
¿Cómo trasladar una imagen con OpenCV?, para poder trasladar una imagen usando OpenCV, debemos recordar que este trabaja bajo coordenadas, x e y. El eje x empieza desde la parte superior izquierda de la imagen hacía la derecha, mientras que el eje y estará presente desde la parte superior izquierda hacía abajo, tal y como podemos apreciar en la siguiente figura:
Para aplicar esta transformación geométrica (traslación) necesitaremos de: matriz M y de la función cv2.warpAffine.
Matriz M
Esta es una matriz de 2 x 3, en donde la primera fila tercera columna estará el componente en x, y en la segunda fila tercera columna estará el componente en y.
tx, representa el desplazamiento en x.
ty, representa el desplazamiento en y.
cv2.warpAffine
Esta función aplica la transformación afín a una imagen.
Parámetros:
- Imagen de entrada.
- M, matriz de transformación de 2 filas x 3 columnas (2×3).
- Tamaño de la imagen de salida.
Para más información sobre esta función y otros de sus parámetros, puedes visitar la documentación de OpenCV.
Una vez que tenemos estos dos componentes, procedemos a la programación para trasladar la imagen de la figura 1.
import cv2 import numpy as np image = cv2.imread('ave.jpg') ancho = image.shape[1] #columnas alto = image.shape[0] # filas # Traslación M = np.float32([[1,0,100],[0,1,150]]) imageOut = cv2.warpAffine(image,M,(ancho,alto)) cv2.imshow('Imagen de entrada',image) cv2.imshow('Imagen de salida',imageOut) cv2.waitKey(0) cv2.destroyAllWindows()
Línea 1 y 2: Importamos OpenCV y numpy.
Línea 4: Leemos la imagen de entrada.
Línea 5 y 6: Ayudándonos de shape
obtenemos el ancho y alto de la imagen. Otro enfoque que podrías usar es el de filas y columnas que componen la imagen, para ello el ancho corresponderá al número de columnas, mientras que el alto al número de filas.
Línea 9: Construimos la matriz M que habíamos descrito antes, para ello usamos np.float32
, y dentro de este especificamos dicha matriz. En este caso aplicaríamos una traslación en x de 100 y en y de 150.
Línea 10: Usamos la función cv2.warpAffine
. Como primer argumento tenemos la imagen de entrada, luego la matriz M, y finalmente el ancho y alto de la imagen de salida.
Líneas 12 a 15: Visualizamos las imágenes de entrada y salida. Luego esperamos a que una tecla sea presionada, para finalmente cerrar todas las ventanas.
La visualización que tendríamos es la siguiente:
Puedes experimentar con distintos valores para el desplazamiento de la imagen en x e y, incluso con valores negativos, como puedes ver a continuación:
Rotando una imagen
¿Cómo rotar una imagen usando OpenCV? Al igual que con la traslación, vamos a necesitar una matriz en donde se especifique el ángulo de rotación a la que va a ser sometida la imagen, para ello vamos a usar la función cv2.getRotationMatrix2D y posteriormente cv2.warpAffine. Esta última función ya fue explicada en el apartado anterior, por lo tanto nos centraremos en como obtener la matriz de rotación.
cv2.getRotationMatrix2D
Esta función calcula una matriz afín de rotación 2D, además permite ajustar el centro de rotación, así como la escala de la imagen.
Parámetros:
- Centro de rotación de la imagen de entrada.
- Ángulo de rotación en grados (rotación en sentido antihorario).
- Escala, valor de escala isotrópica.
Para más información sobre esta función dirígete a este link.
Ahora veremos la programación:
import cv2 import numpy as np image = cv2.imread('ave.jpg') ancho = image.shape[1] #columnas alto = image.shape[0] # filas # Rotación M = cv2.getRotationMatrix2D((ancho//2,alto//2),15,1) imageOut = cv2.warpAffine(image,M,(ancho,alto)) cv2.imshow('Imagen de entrada',image) cv2.imshow('Imagen de salida',imageOut) cv2.waitKey(0) cv2.destroyAllWindows()
Como podrás haberte dado cuenta líneas de 1 a 6 y de 12 a 15 son idénticas al apartado anterior, por lo que me centraré en las líneas 9 y 10.
Línea 9: Aquí procedemos a especificar los argumentos para calcular la matriz afín de rotación 2D usando cv2.getRotationMatrix2D
. Como primer argumento está el centro de rotación (en este caso el centro de la imagen), para encontrar las coordenadas correspondientes se ha obtenido la mitad del ancho y alto de la imagen (ancho//2,alto//2)
. El siguiente argumento es el ángulo de rotación, en este caso 15
grados. Finalmente se ha conservado 1
para el escalado, de tal modo que permanezca el mismo tamaño de la imagen.
Recuerda que puedes probar con distintos valores para cada uno de los argumentos, he ir experimentando un poco con los resultados que arroje esta función.
Línea 10: Del mismo modo que con la traslación, usaremos la función cv2.warpAffine
en donde como primer argumento estará la imagen de entrada, luego M correspondiente a la matriz de rotación creada en la línea 9, y finalmente el ancho y alto de la imagen de salida.
Obtendremos lo siguiente:
También podrías probar la rotación con ángulos negativos, veamos:
Escalando una imagen
¿Cómo escalar una imagen?. Ya sea si necesitas agrandar o disminuir el tamaño de una imagen, OpenCV ofrece la función cv2.resize
para poder hacerlo, pero a más de esta librería también te voy a hablar de imutils.resize
, realizada por Adrian Rosebrcok de pyimagesearch que en mi opinión puede facilitar el redimensionamiento de una imagen.
cv2.resize
Esta función cambia el tamaño de una imagen.
Parámetros:
- Imagen de entrada.
- (ancho, alto) que se le quiere dar a la nueva imagen.
- Método de interpolación. (Banderas de interpolación que puedes usar)
Para otros parámetros y más información sobre esta función, por favor visita la documentación de OpeCV.
Vamos con la programación:
import cv2 image = cv2.imread('ave.jpg') # Escalando una imagen imageOut = cv2.resize(image,(600,300), interpolation=cv2.INTER_CUBIC) cv2.imshow('Imagen de entrada',image) cv2.imshow('Imagen de salida',imageOut) cv2.waitKey(0) cv2.destroyAllWindows()
Línea 1: Importamos OpenCV.
Línea 3: Leemos la imagen de entrada.
Línea 6: Usamos cv2.resize
para realizar el escalado de la imagen. Como primer argumento tendremos la imagen de entrada, luego especificamos un ancho de 600 y alto de 300 para la nueva imagen, por último especificamos un método de interpolación.
Línea 8 a 11: Finalmente visualizamos la imagen de entrada y la imagen de salida. Esperamos que una tecla sea presionada y cuando esto pase se cerrarán todas las ventanas.
Tendríamos la siguiente visualización:
Como puedes ver en la figura 8 en la imagen de la derecha, hemos podido redimensionar la imagen, sin embargo esta parece un tanto extraña, y es que hay que tener en cuenta algo, al realizar este ejemplo no hemos considerado el aspect ratio de la imagen, simplemente hemos redimensionado con valores arbitrarios, lo cual hizo que la imagen se distorsione un poco.
Este efecto puede ser corregido considerando el aspect ratio de la imagen, que llevaría un par de líneas de código. Otra opción que podrías tomar es usar imutils.resize que veremos a continuación.
imutils.resize
Imutils es un paquete que contiene una serie de funciones para realizar procesamiento de imágenes tales como traslación, rotación, entre otros. En esta ocasión únicamente me centraré en la función para el redimensionamiento de imágenes, pero si quieres saber más sobre este paquete y como usarlo puedes dirigirte a su repositorio en github.
NOTA: Para instalar imutils puedes usar pip install imutils
.
Pero te peguntarás, ¿qué tiene de diferente esta función?, o ¿por qué hablas de ella?. Pues bien, usando imutils.resize debes indicar la imagen que va a ser procesada y el alto o ancho que deseas obtener, y automáticamente te devolverá una imagen con el alto o ancho que hayas indicado respetando el aspect ratio de la imagen evitando que la imagen se distorcione (aparezca alargada o achatada), veamos:
Parámetros:
- Imagen de entrada.
- width (ancho) o height (alto) de la imagen de salida.
¡Lo entenderemos mejor con la programación!, veamos:
import cv2 import imutils image = cv2.imread('ave.jpg') # Escalando una imagen usando imutils.resize imageOut1 = imutils.resize(image,width=300) imageOut2 = imutils.resize(image,height=300) cv2.imshow('Imagen de salida1',imageOut1) cv2.imshow('Imagen de salida2',imageOut2) cv2.waitKey(0) cv2.destroyAllWindows()
Línea 1 y 2: Importamos OpenCV e imutils.
Línea 4: Leemos la imagen de entrada.
Línea 7: Usamos imutils.resize
para redimensionar la imagen de entrada. Especificamos la imagen de entrada y ahora un ancho de 300. Lo que hará esta función es calcular automáticamente el alto de la imagen para que respete el aspect ratio de la imagen.
Línea 8: Realizamos algo similar a la línea 7, con la diferencia que ahora especificaremos, que la imagen se debe escalar a 300 de altura. Entonces la función calculará el ancho correspondiente, para que se respete el aspect ratio de la imagen.
Línea 10 a 13: Vamos a visualizar las imágenes de la línea 7 y 8 para ver como nos va con esta función.
Las imagenes de la figura 9 muestran los resultados al usar imutils.resize
, en donde unicamente tendremos que especificar el ancho u alto de la imagen de salida y esta función calculará su alto u ancho correspondiente.
Recortando una imagen
¿Cómo recortar una imagen? Para recortar una imagen vamos a tratar a esta como una matriz, para ello emplearemos indexación de Numpy, de donde escogeremos las filas y columnas que deseemos recortar de la imagen.
Planteríamos algo como lo siguiente: imagen[fila inicial : fila final, columna inicial : columna final]
Supongamos que de la imagen de entrada (figura 1), vamos a recortar la cabecita del ave. Entonces tendríamos las siguientes líneas de código:
import cv2 image = cv2.imread('ave.jpg') #Recortar una imagen imageOut = image[60:220,280:480] cv2.imshow('Imagen de entrada',image) cv2.imshow('Imagen de salida',imageOut) cv2.waitKey(0) cv2.destroyAllWindows()
Línea 1 y 3: Importamos OpenCV y leemos la imagen de entrada.
Línea 6: En esta línea estaremos recortando la cabeza del ave de la imagen de entrada image
. Para ello establecemos que las filas van de 60:200
, mientras que para las columnas 280:480
.
Líneas 8 a 11: Se realizará la visualización de las imagenes de entrada, y la imagen recortada.
Veamos:
En la imagen derecha de la figura 10 podemos ver la imagen recortada de la cabecita del pajarito. Si bien en la programación establecimos las filas y columnas para determinar este área, fue un proceso de prueba y error hasta conseguir la región deseada. Por lo que en un principio recortar una imagen «al ojo» puede ser un poquito tedioso, pero con práctica se mejorará.
Y hemos llegado al final del post. Hoy vimos como usar las funciones de OpenCV para trasladar, rotar, redimensionar una imagen y finalmente como recortar una porción de la imagen usando la información de filas y columnas. ¡Nos vemos en el siguiente post!.
Referencias:
- https://docs.opencv.org/trunk/da/d6e/tutorial_py_geometric_transformations.html
- https://docs.opencv.org/trunk/da/d54/group__imgproc__transform.html#ga0203d9ee5fcd28d40dbc4a1ea4451983
- https://docs.opencv.org/trunk/da/d54/group__imgproc__transform.html#gafbbc470ce83812914a70abfb604f4326
Qué temas específicos de la matemática son necesarios entender para manejar mejor las librerias?
Hola Sergio, principalmente operaciones con matrices.
Gracias Gaby
Hola Gaby! Me he entretenido mucho en tu canal, gracias por compartir tus conocimientos. Es posible cargar una imagen y que nos muestre las coordenadas del cursor para facilitar el recorte? Creo que vi esto en un video tuyo pero no se cual. Saludos
Hola Christian, muchas gracias! 😀 Se me ocurre que podrías realizarlo con los eventos del mouse, te dejo este video tutorial: https://youtu.be/7fgUnqe2x78 espero que sea de ayuda. 🙂
Hola Gaby, ¿sería posible, con algún pequeño cambio en el código, que la parte de la imagen que queda en negro fuera completada por la parte de la imagen que ya no aparece?
Un saludo y gracias por tu contenido
Perdón, en el apartado de Trasladando una imagen, que no lo había mencionado
Hola Omesitos, he implementando una barra deslizante a la solución,
espero a alguno les sirva:
– traslación
– rotación y cambiar la escala de una imagen.
=======================================================================
import cv2
import imutils
import numpy as np
image = cv2.imread(‘ave.jpg’)
ancho = image.shape[1] # columnas
alto = image.shape[0] # filas
def nothing(value):
pass
cv2.namedWindow(‘Imagen’)
cv2.moveWindow(‘Imagen’, 400, 10)
cv2.createTrackbar(‘Rotation’, ‘Imagen’, 0, 180, nothing)
cv2.createTrackbar(‘Escala’, ‘Imagen’, 100, 800, nothing)
cv2.createTrackbar(‘Move_width’, ‘Imagen’, 0, 490, nothing)
cv2.createTrackbar(‘Move_height’, ‘Imagen’, 0, 328, nothing)
while True:
valAngulo = cv2.getTrackbarPos(‘Rotation’, ‘Imagen’)
valWidth = cv2.getTrackbarPos(‘Escala’, ‘Imagen’)
valMoveX = cv2.getTrackbarPos(‘Move_width’, ‘Imagen’)
valMoveY = cv2.getTrackbarPos(‘Move_height’, ‘Imagen’)
# Como 3er argumento se ha conservado 1 para el escalado,
# de tal modo que permanezca el mismo tamaño de la imagen.
M = cv2.getRotationMatrix2D((ancho//2, alto//2), valAngulo, 1)
imageOut = cv2.warpAffine(image.copy(), M, (ancho, alto))
imageOut = imutils.resize(imageOut, width=valWidth)
imageOut = imutils.resize(imageOut, height=valWidth)
M2 = np.float32([[1, 0, valMoveX], [0, 1, valMoveY]])
imageOut = cv2.warpAffine(imageOut, M2, (ancho, alto))
cv2.imshow(‘imageOut’, imageOut)
cv2.moveWindow(‘imageOut’, 300, 300)
if cv2.waitKey(1) & 0xFF == ord(‘s’):
break
cv2.destroyAllWindows()
Gracias Gabriela por tus códigos. Me fueron muy útiles para micro rotar imagenes en un data set que estoy procesando en una neuronal convolucional en la cual me faltaban imágenes.
buenos dias necesito ayuda con este ejercicio
crear un programa en python que contenga un menú y que reciba una imagen de entrada, y que le permita al usuario hacer alguna de las siguientes transformaciones a la imagen: a) reflexión horizontal b) reflexión vertical c) zoom in 50% y zoom de 150% d) rotación de 30°, 45° y 90°