🖼️ Como trasladar, rotar, escalar y recortar una imagen | Python – OpenCV

Por Administrador

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:

Figura 1: Imagen de entrada.

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:

Figura 2: Coordenadas x e y sobre una imagen usando OpenCV

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:

Figura 3: (Izq) Imagen de entrada. (Der) Imagen de salida luego de aplicar traslación.

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:

Figura 4: Pruebas de traslaciones sobre la imagen de entrada.

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:

Figura 5: (Izq) Imagen de entrada. (Der) Imagen de salida luego de aplicar 15 grados de rotación.

También podrías probar la rotación con ángulos negativos, veamos:

Figura 6: Prueba de imagen a -130 grados de rotación

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)

Figura 7: Banderas de interpolación.

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:

Figura 8: (Izq) Imagen de entrada. (Der) Imagen de salida luego de cambiar las dimensiones de la imagen.

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.

Figura 9: (Izq) Imagen de salida ‘imageOut1’, en donde se ha redimensionado la imagen de entrada, especificando un ancho de 300 pixeles. (Der) Imagen de salida ‘imageOut1’ en donde se ha redimensionado la imagen de entrada a un alto de 300 pixeles.

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:

Figura 10: (Izq) Imagen de entrada. (Der) Imagen de salida luego de recortar la imagen.

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