Patchify es una librería muy simple, que nos proporciona tan solo dos funciones que nos harán la vida más fácil cuando necesitemos trabajar con pequeños recortes de imágenes de gran tamaño. Éstas son: patchify y unpatchify.

Dichas funciones nos permiten “trocear” las imágenes en porciones iguales y luego volverlas a “ensamblar” de manera sencilla. En el caso de las imágenes de satélite o aéreas, puede suceder que partamos de una imagen grande y deseemos obtener una serie de imágenes más pequeñas. Esto puede ser útil, por ejemplo, a la hora entrenar modelos para la detección de objetos o segmentación semántica, donde podemos desear obtener una serie de imágenes con las mismas dimensiones y otra serie imágenes clasificadas o “máscaras” cuyos píxeles se correspondan con las imágenes originales.

En este ejemplo trabajamos con una ortoimagen de la ciudad de Munich descargada de su servicio WMS.

Empezamos importando las librerías que vamos a usar:

Además de Patchify usaremos:

PIL: función Image para leer la imagen.
Matplotlib: función pyplot para las representaciones gráficas.
Numpy: para el manejo de arrays.

Partimos de una imagen en formato .png, que al ser leída con la función Image de PIL, nos crea un objeto Image de dimensiones (5000, 3000), que representan los píxeles que se encuentran en el eje x, seguidos de los del eje y. Como necesitamos transformarlo a un array, usamos numpy.array(image) para obtener un array tridimensional con 3 bandas (RGB), siendo ahora sus dimensiones (3000, 5000, 3).

Dividir la imagen con Patchify será tan sencillo como llamar a la función patchify introduciento como parámetros la variable que contiene el array de la imagen, una tupla con las dimensiones que queremos recortar y un tamaño de paso o “step” que nos indicará el número de píxeles en horizontal y vertical que avanzará para realizar un nuevo recorte desde las coordenadas en las que hizo el anterior. Para realizar una sucesión de recortes sin solapamientos y sin saltarse píxeles entre ellos, los recortes deben ser cuadrados y el tamaño de paso igual que el número de píxeles que estos tengan de lado.

Realizamos dos cortes sin solapamientos a la imagen, uno de los cortes creará imágenes cuadradas con 500 píxeles de lado y otra con 256.

Los recortes o “patches” se nos almacenan en sendas variables de 5 dimensiones que nos indican que una tiene unas dimensiones (11, 19, 256, 256, 3) 11 recortes en el eje vertical, 19 en el horizontal, que son 1 imagen de 256×256 con 3 bandas. Mientras que al recortar en 500×500 píxeles hemos generado 6 recortes en vertical y 19 en horizontal.

Podemos seleccionar el recorte con el que queramos por sus coordenadas, siendo el primer recorte el de la esquina superior izquierda el (0,0), siendo así el de la esquina inferior derecha el (10, 18) en el caso del recorte de 256 píxeles. Para seleccionarlo debemos señalarlo en la variable que almacene los “patches”, situando cuatro parámetros en los que los dos primeros serán las coordenadas que indican la posición del píxel en los ejes x e y respectivamente.

Esto nos crea un un array de cuatro dimensiones, en la que una de ellas no resulta de utilidad y nos impide que matplotlib represente la imagen, es para librarnos de esta dimensión que utilizamos la función squeeze de numpy, que nos elimina todas las dimensiones de tamaño 1.

Ahora que sabemos localizar un recorte, también podríamos construir un bucle “for” que recorriese todos los “patches” para hacer lo que queramos con ellos.

Reconstruir con Patchify las imágenes a partir de los recortes es tan sencillo como fue crearlos. Para ello tendremos que llamar a la función “unpatchify” introduciendo como parámetros la variable donde están almacenados los recortes y la dimensión de la imagen resultante de la recontrucción, teniendo en cuenta que ésta no tiene por qué ser la misma que la de la imagen original.

En nuestro caso hemos realizado dos tipos de recorte, uno con cuadrados de 500 píxeles de lado, cuyas dimensiones al juntar todos los “patches” casa con la imagen original y otro con cuadrados de lado igual a 256 píxeles, que no lo hace. En el primero tendremos una imagen con las mismas propiedades que la original, pero en el segundo caso obtenemos una imagen que en vez de tener 3000×5000, ahora tiene 2816×4864 píxeles.

Para obtener, en el segundo caso, una imagen con las mismas dimensiones que la original, deberíamos “rellenar” el espacio hasta lograr una imagen con las mismas dimensiones que la original. Para ello creamos un array de ceros para después sustituir aquellos que corresponden con píxeles de la imagen reconstruida por valores de estos últimos. En el caso de que se nos pidiese un array de formato distinto al que obtenemos, como en este caso teníamos un array con formato int32, mientras matplotlib nos pedía para guardar la imagen RGB un formato uint8, llegaría con llamar a la función astype sobre el objeto de la imagen y darle el formato deseado como se puede ver en la última línea de la imagen que se muestra a continuación.

De todas maneras, si queremos tener georreferenciada la nueva imagen sin tener que hacerlo manualmente, podemos copiar el archivo auxiliar que contiene las transformaciones de la imagen original y darle el nombre correspondiente con la nueva imagen de salida y aunque no coincidan los tamaños, al realizar las mismas transformaciones, vemos que la imagen queda perfectamente georreferenciada de nuevo.

Podemos observar como la imagen (en amarillo) queda posicionada exactamente igual en ambos casos.

Además, unpatchify, sólo entiende de dimensiones y sirve también para unir arrays que contengan recortes obtenidos por otros métodos, siempre que se respeten las dimensiones requeridas.

1 estrella2 estrellas3 estrellas4 estrellas5 estrellas (4 votos, promedio: 4,75 de 5)

Cargando...

Formación de calidad impartida por profesionales