El efecto de transición entre imágenes disolver o ‘dissolve’ consiste en una interpolación desde la imagen inicial hasta la imagen final en un periodo de tiempo determinado.
Para ello se definirá un parámetro t, que representa el progreso de la transición y cuyo rango es de 0 a 1. Un valor de cero significa que la transición aún no ha comenzado, es decir, aún se muestra completamente la imagen de origen, mientras que un valor de 1 significa que se ha completado el 100% de la transición, es decir, se mostrará la imagen de destino. Un valor de 0.5 significaría que la transición está al 50% por lo que se mostraría una mezcla a partes iguales de la imagen de origen y la imagen de destino.
Para su implementación se utilizará un WriteableBitmap. Los pixeles de un WriteableBitmap en Silverlight se representan como valores pargb lo que implica que el canal alpha, encargado de representar el nivel de opacidad, debe ir premultiplicado por lo que para representar un color rojo 50% transparente el pixel debería contener los valores [0.5,0.5,0,0]. De todas formas, para el caso que nos ocupa simplemente realizaremos la interpolación entre cada uno de los componentes de cada pixel de la imagen.
Si representamos cada pixel como un vector de cuatro componentes, siendo tr el vector que representa a un pixel de la transición, o a uno de la imagen de origen y d a uno de la imagen de destino el calculo de cada uno de los pixeles de la transición para un t dado se realiza mediante la siguiente expresión:
siendo x,y las coordenadas del pixel.
El siguiente programa en Silverlight muestra el efecto de transición con dos imagenes predefinidas.
El código fuente del programa se encuentra adjunto al artículo.
Una de las novedades introducidas en la versión 3 de Silverlight es la clase WriteableBitmap que nos permite la generación dinámica de mapas de bits o bitmaps.
Su funcionamiento es muy sencillo, basta con pasar en el constructor el número de pixels de ancho y de alto que queremos que tenga la imagen para generarla y una vez generada podemos acceder a su contenido a través de la propiedad Pixels.
En el siguiente fragmento de código se construye un bitmap de 320×200 pixels y se establece el pixel en la posición (x, y) al color (r,g,b). Una vez modificado el bitmap se debe llamar a la función Invalidate para actualizar su contenido.
3: bitmap.Pixels[x + y * bitmap.PixelWidth] = pixelColor;
4: bitmap.Invalidate();
Por supuesto es necesario asignar el bitmap a la propiedad Source de un control Image para representarle en pantalla.
Una funcionalidad interesante añadida es el método Render que permite representar en el bitmap un control gráfico descendiente de UIElement después de aplicarle una transformación (rotación,escala,posición) lo que abre la puerta a la generación de interesantes efectos.
La siguiente ilustración muestra la generación dinámica de bitmaps. Si posa el cursor sobre la imagen podrá ver una representación de metaballs construida sobre un WriteableBitmap.
La ilusión ‘Stepping feet’ que yo he traducido como pasito a pasito fue presentada por Stuart Anstis en 2003.
Se observa que cuando las bandas negras y grises están presentes ambos objetos parecen desplazarse fuera de sincronía mientras que cuando se quitan las bandas se puede apreciar como en realidad ambos objetos se mueven a la par de forma suave.
En el siguiente programa escrito con JavaScript utilizando jQuery se puede observar el efecto.
En la excelente página de Michael Bach de donde se inspiró este programa se puede encontrar más información sobre el efecto así como un applet más sofisticado que permite modificar sus parámetros.
Utilizando la técnica descrita en el artículo anterior se ha representado el contenido espectral de una canción en una estructura tridimensional. Para ello se representa el espectro de cada pequeño tramo temporal de la canción en la cara frontal del cubo desplazándose en profundidad a medida que pasa el tiempo y va llegando nuevo contenido espectral.
El resultado se observa a continuación aunque la calidad del video no es demasiado buena y se observan inconsistencias en el framerate que ‘estropean’ la continuidad del efecto.
Cada plano del eje Z o de profundidad representa a un espectro. Cada espectro se representa en cada plano X-Y del volumen modificándose ligeramente de forma aleatoria el contenido del eje Y o altura con objeto de mejorar la estética del efecto. Con el mismo objetivo se aplica una pequeño efecto de escala al volumen que representa la energía promedio del espectro del intervalo de la canción que esta sonando en ese instante.
El sonido pertenece a un fragmento de uno de los episodios de la cuarta temporada de Battlestar Galactica y ha sido extraído de aquí.
La representación volumétrica es una técnica que permite la representación de campos escalares tridimensionales. Sus aplicaciones son múltiples: representación de imágenes del cuerpo humano procedentes de diversos instrumentos sensores con fines médicos, representación realista de nubes u otros fenómenos gaseosos en simulaciones visuales en entornos virtuales, o representación de diversas estructuras y constructos en la ciencia y la ingeniería.
En este artículo se describirá una variante de la técnica basada en texturas conocida como ‘volume ray casting’. Conceptualmente dicha técnica consiste en el lanzamiento de rayos con origen en la cámara de tal forma que atraviesen el volumen que contiene el campo escalar. El color resultante que se ‘pintará’ en la superficie del volumen en el punto de entrada de cada rayo será una función de los puntos que el rayo atravesó al pasar por el volumen.
Para su implementación se utilizará la plataforma XNA y se hará uso de la aceleración grafica que nos proporcionan la GPU. Será necesaria una tarjeta que soporte al menos la versión 3.0 del modelo de sombreadores (Shader Model 3.0).
El proceso comienza con la representación de un volumen que actuará como frontera del campo escalar, es decir, el campo escalar se encontrará completamente en el interior de ese volumen. Utilizaremos un cubo.
En primer lugar representaremos las posiciones de entrada del rayo y de salida en dos texturas que posteriormente utilizaremos para determinar la dirección. Al Vertex Shader en la GPU se le harán llegar las posiciones sin transformar de los vértices del cubo. Dichas coordenadas se copiaran a la variable InterpolatedPosition a la salida del Vertex Shader. Dicha variable está marcada como coordenadas de textura por lo que a la entrada del pixel shader se recibiran las coordenadas interpoladas. Lo mismo se hará para la variable InterpolatedTransformedPosition solo que en este caso almacenaremos las coordenadas transformadas por la combinación de las matrices de posicionamiento en el mundo (world), vista (view) y proyección (projection) que serán suministradas a la entrada del programa de la GPU como parámetros. Esta última variable será utilizada posteriormente para localizar la posición exacta donde se deben muestrear las texturas para obtener la dirección del rayo.
Se representarán las caras frontales del cubo en una textura utilizando el estado de representación CullMode.CounterClockWise. El color asignado a la textura en realidad contiene las coordenadas tridimensionades del cubo en el espacio de coordenadas local del modelo en el formato (x,y,z,1).
A continuación se repite la operación pero esta vez representando las caras interiores del cubo.
El siguiente y ultimo paso es la representación del cubo, solo que en esta ocasión el color resultante será función del campo escalar, muestreado en base a las direcciones grabadas en las texturas anteriores. Al muestrear cada una de las texturas anteriores podemos obtener para cada punto (x,y) de la textura, las coordenadas (x,y,z) del cubo por las cuales entró el rayo y por las cuales salió. Con estas dos coordenadas se puede calcular la dirección del rayo y al conocer el punto inicial y la dirección del rayo que atraviesa el campo escalar se puede recorrer cada uno de los puntos de ese campo para calcular su contribución al color de la superficie del cubo. Este proceso se realiza en el Pixel Shader que representará el resultado final en pantalla.
13float3 direction = normalize(backPos – frontPos);
14//Inicializamos las variables del color
15float4 color = float4(0, 0, 0, 0);
16float4 src = 0;
17float value = 0;
18//Recorremos el campo escalar en la dirección calculada
19//acumulando opacidad en función del campo
20float3 Step = direction * (1.0f/256.0f);
21for(int i = 0; i < 256; i++)
22 {
23//muestreamos la textura
24 value = tex3Dlod(VolumeTextureSampler, currentPosition).r;
25 src = (float4)value;
26//Front to back blending
27 src.rgb *= src.a;
28 color = (1.0f – color.a)*src + color;
29//advance the current position
30 currentPosition.xyz += Step;
31 }
32return color;
33 }
El rendimiento de esta técnica al ser completamente acelerada por GPU es muy bueno como se puede constatar en los siguientes videos obtenidos con una tarjeta gráfica de gama media/baja con un consumo de CPU mínimo.
Color Hunter permite obtener paletas de color extraídas automáticamente de imágenes en flickr que concuerden con nuestro criterio de búsqueda, por lo que podemos buscar paletas de color vinculadas a determinadas palabras.
La percepción del color se encuentra fuertemente influenciada por el contexto. Dos regiones desde las que se observa la misma luz (mismo espectro de radiación electromagnética) nos pueden parecer diferentes dependiendo del entorno que las rodea, fenómeno conocido como contraste de color (Figura A). De la misma forma, regiones de objetos que reflejan, transmiten o emiten espectros de luz diferentes podrían parecer del mismo color, fenómeno conocido como constancia de color (Figura B).
En la figura A se observa como los dos recuadros de idéntica reflectancia que se muestran en la parte inferior en ausencia de contexto, parecen tener colores muy diferentes. En la figura B, los recuadros tienen distinta reflectancia y a pesar de ello parecen tener el mismo color. Puede comprobarlo utilizando un programa de tratamiento de imagen y midiendo los valores RGB que presenta su monitor en dichas áreas.
El fenómeno de la constancia de color ha fascinado a multitud de científicos. Aunque estos fenómenos eran bien conocidos en el siglo 19 no adquirieron un lugar central en la teoría de la percepción del color hasta los trabajos de Land en la década de los 50.
Edwin H. Land, fundador de la compañía Polaroid es uno de los más famosos investigadores en el área de la constancia de color. En 1959 realizó una serie de experimentos con resultados bastante asombrosos después de los cuales desarrollo, junto con John J. McCann uno de los primeros modelos computaciones de constancia de color, la teoría retinex.
De acuerdo a la teoría retinex, el procesado de la información visual comienza con los receptores de la retina. Dentro de la retina, tres tipos de sensores miden la luz en las partes roja, verde y azul del espectro. Esta información visual es posteriormente procesada de forma independiente para cada banda de color.
En sus experimentos utilizaban estímulos similares a las famosas pinturas del artista Piet Mondrian, parecidas a la imagen que se muestra a continuación, que componían colocando papeles coloreados sobre un lienzo de forma aleatoria. Al conjunto se le aplicaba una capa mate para reducir los posibles efectos de la reflectancia especular.
Para iluminar el mondrian se utilizaban tres proyectores con un filtro paso banda estrecho. El primer filtro permitía el paso de la luz de longitudes de onda corta (luz azul), el segundo permitía longitudes de onda medias (luz verde), y el tercero permitía el paso a las longitudes de onda largas (luz roja). La cantidad de luz emitida por cada proyector se podía controlar.
Se encendían todos los proyectores y se ajustaban para que cada papel coloreado del mondrian pareciera fuertemente coloreados, buscando sobre todo que los papeles blancos parecieran ‘buenos blancos’.
Posteriormente se utilizaba un fotómetro telescópico para medir la luz reflejada por un área determinada dentro del mondrian. Ellos seleccionaron un rectángulo blanco y midieron la luz que reflejaba (la luminancia) para cada uno de los tres proyectores, es decir, se hicieron tres mediciones cada una con uno solo de los proyectores encendido.
A continuación se eligió un rectángulo que parecía marrón oscuro y ajustaron los proyectores de luz para que los resultados fueran idénticos a las medidas anteriores.
Incluso aunque la luminancia media era equivalente a la del rectángulo blanco, es decir, el objeto estaba reflejando la misma luz que reflejaba el parche blanco cuando le medimos, el color seguía siendo percibido como marrón oscuro. Se repitió el experimento para los diferentes colores y en cada uno de los casos es color percibido permanecía constante.
Con este experimento, Land y McCann demostraron que el color percibido en un área de una imagen no depende exclusivamente de la luz observada en esa área.
Los algoritmos genéticos están inspirados en la teoría de la evolución de Darwin y forman parte de la computación evolutiva, área de rápido crecimiento dentro del campo de la inteligencia artificial.
Los seres vivos están compuestos por células. En cada una de la células de un organismo se encuentra el mismo conjunto de cromosomas. Los cromosomas son cadenas de ADN y sirven como modelo para el organismo, es decir, el organismo se construirá o desarrollará en base a las instrucciones codificadas en su cromosomas.
Un cromosoma está compuesto por genes, bloques de ADN. Cada gen codifica una proteína particular. Se podría decir que cada gen codifica un rasgo, como por ejemplo el color de los ojos. Los diferentes rasgos son llamados alelos (ojos azules, ojos marrones). Cada gen tiene su propia posición dentro del cromosoma.
El conjunto completo de material genético (todos los cromosomas) es llamado genoma. Un conjunto particular de genes del genoma se llama genotipo. El genotipo es la base para el fenotipo, las características físicas y mentales que presentara el organismo al desarrollarse.
Durante la reproducción, el material genético de cada uno de los padres se recombina al formarse los gametos, células cuyo material genético se fusionará en la fecundación. Existe un complicado conjunto de sistemas encargados de asegurar la integridad de la molécula de ADN con el fin de preservar la información hereditaria y reparar la mayor parte de las alteraciones que pueda experimentar, sin embargo, aproximadamente uno de cada mil errores no es corregido por lo que la información se ve alterada de una generación a la siguiente apareciendo lo que se denomina mutación, que hace referencia a cualquier cambio permanente en el material génico no debido a la segregación independiente de los cromosomas o a la recombinación que ocurre durante el proceso de meiosis.
Las mutaciones se producen al azar y son generalmente perjudiciales, aunque en ocasiones también ocurren mutaciones beneficiosas que confieren alguna ventaja a las células en las que aparecen.
Tanto las recombinaciones como las mutaciones beneficiosas son las causas de las grandes variaciones que muestran los individuos de una misma especie. Los individuos que presenten una mejor adaptación a su entorno es más probable que tengan descendientes formados en base a su material genético.
Los algoritmos genéticos permiten encontrar buenas soluciones para una clase de problemas cuya solución sería difícil de encontrar utilizando otros métodos. Conceptualmente establecen una analogía entre el conjunto de soluciones de un problema y el conjunto de individuos de una población. Cada individuo representa una posible solución al problema y se parte de un conjunto de individuos normalmente generado al azar que se hará evolucionar de tal forma que las nuevas generaciones contengan soluciones mejores para el problema a resolver.
De forma general el proceso es el siguiente:
Generar una población aleatoria de n cromosomas (posibles soluciones al problema).
Evaluar la adaptación f(x) de cada cromosoma x en la población. Dicha función evaluara la bondad de la solución que presenta cada cromosoma.
Si se cumple la condición de finalización (típicamente el haber encontrado una solución aceptable o llegar a un número de generaciones máximo) detener el algoritmo.
Generar una nueva población. El proceso de crear una nueva generación típicamente se divide en cuatro pasos: Selección, Cruzamiento, Mutación y reemplazo.
Reemplazar la antigua generación por la nueva.
Ir al paso 2.
Un ejemplo de resolución de este tipo de problemas lo encontramos en la reciente implementación por Roger Alsing de un algoritmo genético para aproximar una imagen utilizando un número pequeño de polígonos traslucidos.
El funcionamiento del algoritmo, variante del proceso descrito anteriormente, se puede resumir en los siguientes pasos, tal y como Roger describe en su blog:
Generar una cadena de ADN de forma aleatoria. Esta cadena contendrá las instrucciones para pintar cada uno de los polígonos que aparecen en pantalla.
Generar una nueva cadena de ADN copiando la cadena de ADN anterior mutándola ligeramente.
Utilizar la cadena para representar los polígonos en pantalla.
Comparar el resultado con la imagen original.
Si la nueva imagen se parece más a la imagen original sobrescribir la cadena de ADN original con la nueva cadena.
Repetir desde 1.
Se puso su implementación a prueba con una imagen arbitraria y se dejo evolucionar al ‘organismo’ durante aproximadamente media hora. En el siguiente video se puede ver el proceso de evolución acelerado por un factor de 32.
La imagen final generada se corresponde con la generación 117653 y está compuesta por un total de 78 polígonos con una media de 8 puntos por polígono.
Fiji es un proyecto experimental que permite ejecutar aplicaciones Silverlight fuera del navegador, es decir, como aplicaciones de escritorio en su propia ventana. Su objetivo final es coger los archivos de aplicación (.xap) de Silverlight y utilizarles para generar un archivo ejecutable que no necesite del navegador para funcionar.
Para ello se utiliza el mismo mecanismo que algunos navegadores utilizan para cargar sus plugins, NPAPI (Netscape Plugin API).
Para utilizar Fiji solo es necesario pasarle como parámetro la ruta completa del archivo .xap que contiene la aplicación Silverlight, por ejemplo, “fiji.exe C:\AplicacionSilverlight.xap”.
El fenómeno de la sincronización nos rodea: nuestro corazón, los ritmos circadianos, aplausos, generadores eléctricos… Ciertas especies de luciérnagas han cautivado a muchos viajeros en el Sudoeste Asiático, los cuales regresaban a sus lugares de origen contando historias de poblaciones inmensas de luciérnagas emitiendo luz intermitente de forma totalmente sincronizada creando grandes franjas de luz parpadeante en la oscuridad.
Su estudio se remonta a 1665, cuando Christiaan Huygens yacía enfermo en la cama con la compañía de dos relojes de péndulo. Después de unos días se dio cuenta de que los péndulos se movían de tal forma que cuando uno estaba completamente a la izquierda, el otro se encontraba completamente a la derecha, y viceversa.
Intrigado, modifico manualmente el ritmo de los péndulos pero con el tiempo siempre volvían a sincronizarse. La explicación que dio a lo que el llamaba “simpatía de dos relojes” fue que cada uno de los péndulos causaba un movimiento imperceptible en la pared de la que colgaba cada reloj y que dicho movimiento tendía a forzar la sincronización de de cada uno de los péndulos con el otro. El tiempo le daría la razón.
En el siguiente video se puede observar una versión de este fenómeno (con sonido se aprecia mejor).
El modelo Kuramoto fue motivado por el comportamiento de ciertos osciladores químicos y biológicos y permite modelar la sincronización y desincronización en grupos de osciladores acoplados. La ecuación que gobierna el sistema es la siguiente:
La limitada variedad de estados en los que el modelo se puede encontrar lo hace apropiado para el modelado de algunos sistemas utilizados en neurociencia.
En la siguiente aplicación, cuyo código se encuentra adjunto, puede observar como varía el comportamiento de 25 osciladores en función de la constante de acoplamiento (K). Al reiniciar la simulación se asignarán velocidades y fases iniciales aleatorias a cada uno de los osciladores.