Escalado de imágenes mediante interpolación de vecinos cercanos | Image scaling applying nearest neighbor interpolation

Repo: https://github.com/umarquez/100DaysOfC0D3/tree/master/16-nearest-neighbor-interpolation

¿Qué pasa si queremos hacer una imagen más grande? ¿cómo es que los programas de edición hacen para cambiar el tamaño o hacer zoom en una foto?

La interpolación es el problema de aproximar el valor de una función para un no-dado el punto en el espacio cuando se administra el valor de esa función en puntos alrededor (vecinos) de ese punto. El algoritmo del vecino más cercano selecciona el valor del punto más cercano y no tiene en cuenta los valores de puntos vecinos, produciendo un interpolante constante por trozos. https://es.wikipedia.org/wiki/Interpolaci%C3%B3n_por_el_vecino_m%C3%A1s_cercano

Este método consiste en construir una imagen de mayores dimensiones a partir de una imagen dada, generando la información faltante a partir de la existente en la imagen original; específicamente este método utiliza el color del píxel más cercano al que estamos procesando como relleno de este.

  • El diagrama muestra un escalado del 300% (3:1) , quiere decir que cada pixel original genera un cuadro de 3x3 como resultado.
  • Supongamos que las letras mayúsculas son los píxeles con los colores originales.
  • Las letras minúsculas representan la propagación del color hacia los píxeles nuevos, producto del escalado.
  • Si el escalado fuera mayor, deberemos calcular la distancia de cada nuevo píxel con cada pixel original para obtener el color correspondiente, esto tomaría mucho tiempo de procesamiento por lo que deberemos encontrar algún método de optimización que funcione en distintos casos.

Idealmente podríamos colocar cada píxel original en el centro de cada grupo de pixeles nuevos para poder tener una distribución uniforme de color, como en el diagrama anterior, pero esto requerirá desplazar cada posición <factor> / 2 píxeles tanto horizontal como verticalmente, además de realizar el cálculo de cada hipotenusa por cada píxel…

Aprovechando el tipado de Go

Una forma de abordad este problema que nos puede ahorrar muchos ciclos de procesador y tiempo de cálculo consiste en:

  1. Generar una imagen vacía del tamaño resultante de multiplicar el factor de escalado por el alto/ancho de la imagen original: width * scaleFactor height * scaleFactor
  2. Una vez que generamos la imagen, recorremos todos los píxeles de la nueva imagen a lo ancho y a lo alto (puede ser con un ciclo doble x y y, por ejemplo).
  3. Por cada píxel, dividimos la posición en x y y entre el factor de escalado, almacenando el resultado en variables de tipo int, estos serán los índices del píxel dentro de la imagen original de donde tomaremos el color para cada nuevo píxel.

Este procedimiento sería igual a colocar el pixel original en la esquina superior izquierda de cada grupo de pixeles y propagando el color de manera diagonal en dirección opuesta, esto es posible debido a que Go solo conserva la parte entera de una división de enteros, descartando los decimales, de esta forma cualquier división que no sea exacta dará como resultado el último entero.

Implementación en Go

Tomaremos una imagen aleatoria de un tamaño pequeño y la escalaremos utilizando este método.