Guillermo Cañedo Ramírez es el ganador del reto de la programación lúdica. Nos da sus generales: soy de Morelia Michoacán, tengo 45 años, me gradué en la carrera de Ingeniería Eléctrica en 1993 y terminé una Maestría en Ciencias en el área de Sistemas Eléctricos de Potencia en 1998, ambas en el Instituto Tecnológico de Morelia. Empecé a programar hace unos hace 20 años en los campos de Métodos Numéricos y Algebra Lineal. Comencé con los lenguajes de programación Turbo C, C++, Delphi y Matlab.
Este reto de los fotomosaicos atrajo a unos cuantos programadores que decidieron meterse de lleno para intentra llevarse el iPod Touch. Los concursantes -me queda claro- tomaron nota de las sugerencias sobre qué hacer para ser el ganador, pero hubo esfuerzos muy interesantes que fueron más allá incluso de las sugerencias.
He aquí el fotomosaico ganador:
Lo interesante de la técnica usada por Guillermo fue la creación de pequeños cubos con imágenes (de la biblioteca dada para trabajar), los cuales están orientados como cubos y que se superponen en las regiones de color de manera adecuada. En ese sentido pensamos que fue el fotomosaico más complejo y original que pudo crearse.
He aquí un fragmento de la imagen ganadora:
Cabe señalar que hubo otros programas estupendos. Por ejemplo, Norberto Hernández hizo éste con celdas hexagonales:
Este es un detalle de los hexágonos:
Tanto Norberto como Guillermo, también hicieron fotomosaicos con tamaños variables de cuadrados. Realmente ambos trabajaron un buen rato en este proyecto. De hecho, aunque Norberto no ganó el iPod, sí se lleva una taza de la Morsa por el esfuerzo realizado. Norberto nos dice que originalmente es de Saltillo, Coahuila. Hizo una maestría en la Universidad Autónoma de Nuevo León. Licenciado en Matemáticas y maestría es en Ingeniería de Sistemas. Actualmente trabaja con problemas de optimización (investigación de operaciones) y más en específico con un problema de planeación de turnos. Nos dice que «desde hace algunos meses he traído, también, la curiosidad por incursionar en el tema de imágenes, y pues aproveché esta oportunidad para aprender un poquito al respecto». Pues estoy seguro que su trabajo le ha dejado muchas enseñanzas.
Otro trabajo interesante fue el de Sergio Avendaño, el cual básicamente usó la idea de hacer un mosaico considerando que las regiones se alternaran como cuando se construye una pared. He aquí su esfuerzo:
He aquí el detalle de esta idea:
Otros concursantes hicieron el fotomosaico más sencillo, el cual sin duda tiene su esfuerzo, pero claramente el ganador hizo mucho más trabajo sobre esta idea y por ello gana el premio.
El código de los ganadores, así como sus creaciones gráficas, pueden descargarse de los siguientes enlaces:
Código fuente y ejecutable de Guillermo Cañedo
Imágenes de Norberto Hernández
Código fuente y ejecutable de Norberto Hernández
Código fuente de Sergio Avendaño
Colección de imágenes usadas en el reto para descargar
Por cierto, he aquí las explicaciones básicas del trabajo que hizo Guillermo, escritas por él mismo:
- Cree un programa cuya función es realizar un preproceso que calcula los promedios de colores de la biblioteca de imágenes y los resultados se guarden en unos archivos de texto para posteriormente ser consultados por el programa principal.
- Después en el programa principal, cuando el usuario carga la imagen fuente y se convierte a un mapa de bits, esta se divide en un numero de columnas y renglones con múltiplos de 4, ya que cada cubo esta formado for una submatriz de 4×4, cuya región abarca 3 caras visibles del cubo, pero que en realidad son 3 paralelogramos.
- En el mapa de bits, se rastrean los colores de los pixeles que caen dentro de cada paralelogramo que forman el cubo y se obtiene el color promedio de cada uno y estos se guardan en una lista dinámica de datos.
- Se compara el color promedio de cada paralelogramo con el color promedio de la biblioteca de imágenes y se obtiene el mas cercano o idéntico. De esta manera se obtiene la textura correspondiente para cada cara del cubo.
- Se identifican las texturas repetidas por la posición del cubo y el numero de cara correspondiente, por ejemplo, textura 5, va en el cubo 10, cara 3; cubo 15, cara 1; …cubo 200, cara 2; etc y de esta manera se optimiza el tiempo de carga de la textura desde el archivo guardado en disco.
- Se forma el fotomosaico colocando cada textura en el paralelogramo o cara correspondiente del cubo (aquí se hace una proyección o mapeo de un textura cuadrada sobre una superficie poligonal, cuyos vértices forman el paralelogramo).
Para los que se quedaron con ganas de participar, en unos días lanzaremos el siguiente reto. Estén atentos. Va a ser interesante. Para aquellos que participaron en este reto, les agradezco sus trabajos y tiempo empleado. Es muy satisfactorio ver que hay mucha calidad en los programadores locales y que realmente, en esos términos (en lo que se refiere a software), podemos competir con cualquier programador de cualquier parte del mundo, no me cabe duda.
PostScriptum
Sergio Omar Avendaño Aquino me mandó su programa en PHP y por propia sugerencia de él, incluyo su código fuente y las imágenes que me mandó (ver enlaces más arriba). He aquí sus explicaciones:
Se desarrolló en PHP 5.5.20 con librería gráfica GD integrado en OS X Yosemite,se probó también en un sistema con Linux CentOS 5.5 y PHP versión 5.1.6 con librería GD, en ambos casos los resultados son satisfactorios.
El script contiene una sección inicial que contiene declaraciones de variables las cuales controlan los diferentes aspectos del programa. Para ejecutar el script se necesita una imagen JPG válida, se modifican los valores y se ejecuta desde una terminal Unix con el siguiente comando:
php mosaico.php
El resultado es un archivo JPG con la imagen convertida a fotomosaico.
En la sección inicial del script se encuentran las siguientes variables que controlan los aspectos para generar las imágenes:
$iOriginal – Cadena de texto que contiene el nombre del archivo de la imagen a procesar
$iDestino – Cadena de texto que contiene el nombre del archivo de la imagen resultante
$cAncho – Número entero que indica el ancho de la cuadrícula de la imagen a procesar
$cAlto – Número entero que indica el alto de la cuadrícula de la imagen a procesar
$directorio – Cadena de texto que indica el directorio donde se encuentra la galería de imágenes
$nAncho – Número entero que indica el ancho de los mosaicos de la imagen resultante
$nAlto – Número entero que indica el alto de los mosaicos de la imagen resultante
$fusion – Nivel de Mezcla o Blending, valor entero entre 0 y 100
$repeticion – Valor boolean que indica si los mosaicos se repiten o no (true o false)
$repetir – Si el valor $repeticion es false, este valor indica cuantas imágenes no se repiten antes de comenzar de nuevo
$tabiques – Valor boolean que indica si el proceso simula una pared de ladrillos en los mosaicos de la imagen resultante
Proceso del programa:
Una vez definidas las variables iniciales del programa, el primer paso consiste en verificar si el archivo “diccionario.dat” existe. Este archivo contiene los valores promedio de las imágenes de la librería, si no existe, se calculan los valores promedio de las imágenes y se crea el diccionario para que en una ejecución posterior no se tenga que hacer el proceso de cálculo nuevamente. Si se añaden mas imágenes a la librería, se puede borrar el archivo para que el programa vuelva a generar el diccionario.
Para calcular el promedio de color de una imagen, se barren los pixeles de la misma, se obtienen los componentes RGB de cada pixel y se calcula el promedio de cada componente. Estos se almacenan en un array, junto con el nombre del archivo correspondiente. El diccionario contiene estos valores, por lo tanto, si el archivo diccionario.dat existe, entonces se abre y se leen los mismos almacenando los valores en el mismo array definido anteriormente.
Después de leer la librería de imágenes o el diccionario, se abre la imagen a procesar y se divide en secciones de $cAncho * $cAlto, cada sección se coloca en un buffer de memoria gráfica y se aplica el mismo proceso para calcular el color promedio de la imagen. Posteriormente mediante la ecuación de la distancia en el espacio euclidiano, se barre el promedio de la sección de la imagen contra el diccionario y se hace el cálculo. El valor menor de todos es el que se considera como el correcto o mas aproximado, este proceso obtiene el índice del array donde se encuentra almacenado el nombre del archivo de la galería. A continuación, se crea un buffer de memoria de tamaño $nAncho * $nAlto (previamente se crea una imágen vacía del tamaño total de la imagen resultante), se rellena con el color promedio de la subsección de la imagen original y a continuación se mezcla el archivo de la galeria calculado con dicha sección usando el parámetro $fusion para indicar el nivel de mezcla. El proceso se repite barriendo todas las columnas y filas de $cAncho * $cAlto de la imagen original y se va insertando en la zona que le corresponda en la nueva imagen.
Al final solamente se guarda la imagen resultante en un archivo al 70% de calidad para que el tamaño del archivo JPG resultante no sea excesivamente grande.
El código fuente contiene comentarios para hacerlo mas entendible.
El resultado del programa viene adjunto en el correo. De acuerdo a lo que se indica en el reto, las imágenes resultantes son 9 veces mayores que el original. Aparecen 7 ejemplos del procesamiento, sin embargo se puede jugar con los valores y obtener muchas combinaciones. A continuación indicó que parámetros se usaron en las imágenes adjuntas:
Para todas las imagenes:
$iOriginal = «ilse.jpg»;
$iDestino = «ilse0n.jpg»; // donde n es un consecutivo
$cAncho = 10;
$cAlto = 6;
$directorio=»images»;
$nAncho = 90;
$nAlto = 56;
$fusion = 70;
ilse01.jpg
$repeticion = true;
$repetir = 0;
$tabiques = true;
ilse02.jpg
$repeticion = true;
$repetir = 0;
$tabiques = false;
ilse03.jpg
$repeticion = false;
$repetir = 5;
$tabiques = true;
ilse04.jpg
$repeticion = false;
$repetir = 5;
$tabiques = false;
ilse05.jpg
$repeticion = false;
$repetir = 20;
$tabiques = true;
ilse06.jpg
$repeticion = false;
$repetir = 10;
$tabiques = false;
ilse07.jpg
$repeticion = false;
$repetir = 2;
$tabiques = true;
____
(*) La primera imagen (un fragmento), muestra el uso de cuadrados irregulares del trabajo del ganador, Guillermo Cañedo.