Segundo proyecto: Repintado

Repo: https://github.com/umarquez/100DaysOfC0D3/tree/master/20-repaint

Hemos llegado a la quinta semana y al número 20 de esta serie, en esta ocasión vamos a aprovechar algunas de las funciones del primer proyecto y uno que otro tema tratados hasta el momento, el objetivo será realizar una aplicación que nos ayude a modificar la paleta de colores de una imagen, es decir, vamos a sustituir cada píxel de la imagen con el color de la paleta que más cercano o parecido sea.

Procedimiento

  • Vamos a obtener una serie de paletas de colores desde el sitio: https://lospec.com/palette-list en formato .hex, que no es otra cosa que un archivo de texto con un color RGB en formato hexadecimal en cada línea, o bien, podremos definir nuestra propia paleta utilizando el mismo formato:

cp_rust-5.hex:

230000
712f30
a54932
e18866
f0bb9c
ffe2c6
  • Colocaremos los archivos .hex en un mismo directorio con la finalidad de que nuestro programa obtenga todas las paletas disponibles para generar una imagen de salida por cada paleta.

  • A continuación deberemos obtener una imagen JPEG .jpg aleatoria u obtener una local, esta imagen será la que procesaremos.
  • Leeremos el contenido de la imagen seleccionada y obtendremos el color de cada píxel que la compone.
  • Buscaremos el color obtenido en la tabla de colores ya procesados, esta es una tabla hash que utilizaremos para almacenar el resultado de cada color procesado, esto con el objetivo de solo calcular una vez el sustituto de cada variante y así evitar, por ejemplo, que en una foto con el cielo azul, el mismo tono de azul sea calculado varias veces, en vez de esto, se busca el color original en la tabla y si este ya se encuentra en la tabla, solo se recupera el valor del color sustituto y se evita calcularlo cada vez que se encuentre.

  • Si el color aún no se encontrara en la tabla, deberemos compararlo con cada color disponible en la paleta actual hasta encontrar el sustituto correcto; esto lo haremos encontrando al vecino más próximo utilizando el teorema de Pitágoras pero aplicado a un espacio en 3 dimensiones. Esto es:

    √((R1 - R2)^2 + (G1 - Gg2)^2 + (B1 - B2)^2)

  • Una vez que obtengamos el color sustituto, lo plasmaremos en la imagen resultante en la misma ubicación del píxel evaluado. Esto lo repetiremos hasta haber completado el total de la imagen.

  • La imagen resultante la almacenaremos concatenando el nombre de la paleta utilizada para tener la referencia, una vez hecho esto continuamos con la siguiente paleta.

De esta forma podremos obtener resultados como los siguientes:

Datos de entrada

  • -img Ubicación del archivo de imagen a procesar, si está vacío se tomará una imagen aleatorio de una API, misma que será almacena en el directorio de salida ./out
  • -palettes Directorio desde donde obtendremos los archivos .hex.

Datos de salida

  • Todas las imágenes resultantes serán almacenadas en el mismo directorio de la imagen original.

Implementación en Go

Como dato adicional es importante remarcar que en muchos casos los detalles de la imagen se pierden o se refuerzan, dependiendo de la distribución de los colores de la paleta y de la imagen, es decir, si la imagen cuenta con detalles en tonos similares y la paleta no cuenta con la suficiente cantidad de colores dentro del área en que se encuentran los detalles, estos serán sustituidos por un color sólido, el más cercano al área de los tonos originales; en un caso contrario, podríamos contar con una imagen con un degradado o sombras muy matizadas y con una paleta que cuenta con varias opciones de color cercanos a esos tonos, en este caso la imagen remarcará las sombras lo cual hará que parezcan más contrastadas.

A continuación algunos ejemplos más en donde podemos observarlo.