Siempre he echado en falta que R no disponga de funciones estándar para reescalar imágenes (matrices/arrays). Existen varios paquetes con esta funcionalidad, y uno de ellos que empecé a usar hoy es bueno (calidad de implementación de los algoritmos de interpolación habituales con profusión de opciones de promediado), bonito (intuitivo y fácil de usar) y barato (aceptablemente rápido).
Se trata del paquete terra
, reemplazo del paquete raster
, mucho menos optimizado para esta tarea. Pese a ser un paquete orientado a procesar datos GIS, su implementación del reescalado (función resample()
) de objetos raster es todo lo que necesitamos para cambiar el tamaño de cualquier imagen.
- Un test de tortura frente al aliasing: círculos concéntricos de frecuencia espacial creciente con el radio.
- Un par de imágenes digitales: mapa representado por sus contornos (de 1 píxel de ancho y sin antialiasing aplicado) y una versión "sólida" del mismo.
- Una fotografía: imagen orgánica con profusión de detalle continuo.
Las imágenes de prueba las vamos a reducir primero de sus originales 1.000x1.000 píxeles a 200x200 píxeles cada una, obteniendo el siguiente resultado ampliadas al 200% para apreciar mejor los detalles (imprescindible hacer clic para verlas en su resolución original):
En amarillo las características más reseñables de cada algoritmo en cada tipo de imagen y reescalado. Los artefactos en los bordes de 'cubic' y 'lanczos' son difíciles de ver a simple vista, así que para resaltarlos ponemos aquí en gris medio todo lo que sea blanco o negro puros, mostrando con claridad los nuevos tonos grises que crea cada algoritmo (por eso 'near' aparece en blanco). Tanto 'cubic' como 'lanczos' generan residuos indeseables en los bordes.
Mi elección de algoritmo a priori sería:
- Para gráficos de ordenador (imágenes sintéticas): en las reducciones usaría 'bilinear' por su buen compromiso entre definición y ausencia de artefactos, pero para realizar escalados al alza me decantaría por 'cubic' por su mayor contraste, pese a que puede mostrar artefactos residuales (usando 'near' cuando necesitemos explícitamente un reescalado sin realizar interpolación, por ejemplo para no crear tonos nuevos).
- Para fotografía (lo que incluye mapas raster aéreos y satelitales) usaría siempre 'lanczos' por su mayor nivel de detalle y buena protección frente al aliasing en las reducciones. Sus artefactos no van a ser visibles en imágenes fotográficas y además tras 'cubicspline' es el algoritmo que mejor disimula el pixelado en los aumentos de tamaño.
He dejado para el final la comparativa en cuanto a velocidad de ejecución, ya que pese a existir diferencias en los tiempos todos los algoritmos funcionan aceptablemente rápido, así que difícilmente este parámetro decidirá la elección del método de interpolación.
La mejora respecto al paquete raster es de más de un orden de magnitud (unas 15 veces más rápido). Me sigue chocando no obstante que el reescalado por nearest neighbour ('near'), tenga tiempos cercanos a los verdaderos algoritmos de interpolación, cuando debería ser prácticamente instantáneo ya que solo consiste en tomar muestras de la imagen de partida sin hacer procesado.
arrayresample()
que tomando como parámetros cualquier array a reescalar, las dimensiones de salida y el algoritmo de interpolación, devuelve el array reescalado. Sirve tanto para imágenes en escala de grises (matrices) como en color (array con 3 canales de color). Repositorio con el código R: GitHub.
No hay comentarios:
Publicar un comentario
Por claridad del blog, por favor trata de utilizar una sintaxis lo más correcta posible y no abusar del uso de emoticonos, mayúsculas y similares.