<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mosaic &#187; Recursos</title>
	<atom:link href="http://mosaic.uoc.edu/category/recursos/feed/" rel="self" type="application/rss+xml" />
	<link>http://mosaic.uoc.edu</link>
	<description>tecnologías y comunicación multimedia</description>
	<lastBuildDate>Tue, 18 Jun 2013 07:04:03 +0000</lastBuildDate>
	<language>es-ES</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Device Days</title>
		<link>http://mosaic.uoc.edu/2013/05/29/device-days/</link>
		<comments>http://mosaic.uoc.edu/2013/05/29/device-days/#comments</comments>
		<pubDate>Wed, 29 May 2013 14:08:06 +0000</pubDate>
		<dc:creator>Mosaic</dc:creator>
				<category><![CDATA[Device Days]]></category>
		<category><![CDATA[Número 108]]></category>
		<category><![CDATA[Recursos]]></category>
		<category><![CDATA[diseño]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[móvil]]></category>

		<guid isPermaLink="false">http://mosaic.uoc.edu/?p=13398</guid>
		<description><![CDATA[El pasado 1 de marzo se celebro la quinta edición de Device Days, un evento divulgativo con una clara vertiente formativa sobre el mundo de desarrollo móvil. Presentamos la conferencia sobre Diseño Inclusivo de Tona Monjo, consultora de la UOC y creadora de Latent, empresa de diseño de interfícies multiplataforma.]]></description>
				<content:encoded><![CDATA[<p>El pasado 1 de marzo se celebró la quinta edición de <a href="http://www.blocketpc.com/2013/03/resumen-de-device-days-2013/">Device Days</a>, un evento divulgativo con una clara vertiente formativa sobre el mundo de desarrollo móvil. En la presente edición, las charlas de Device Days contaron nuevamente con el apoyo de Adobe y la colaboración de la UOC.</p>
<p>Teniendo en cuenta el momento álgido que vive la tecnología móvil con un ecosistema cada vez más maduro y con nuevas plataformas como FirefoxOS, Windows Phone 8 o Blackberry 10, la quinta edición de Device Days presentó distintos puntos de vista con especial atención a temas como la Realidad Aumentada, WebGL o Diseño Inclusivo entre otros.</p>
<p>A continuación os presentamos una de las ponencias que tuvo lugar el pasado 1 de marzo dentro del marco de Device Days. Se trata de la conferencia sobre Diseño Inclusivo de Tona Monjo, consultora de la UOC y creadora de Latent, empresa de diseño de interfícies multiplataforma.</p>
<h4>Tona Monjo &#8211; Diseño Inclusivo</h4>
<p><iframe src="http://player.vimeo.com/video/66993645" height="281" width="500" allowfullscreen="" frameborder="0"></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://mosaic.uoc.edu/2013/05/29/device-days/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WebCat: RWD, dealing with navigation</title>
		<link>http://mosaic.uoc.edu/2013/04/24/webcat-rwd-dealing-with-navigation/</link>
		<comments>http://mosaic.uoc.edu/2013/04/24/webcat-rwd-dealing-with-navigation/#comments</comments>
		<pubDate>Wed, 24 Apr 2013 09:24:46 +0000</pubDate>
		<dc:creator>Mosaic</dc:creator>
				<category><![CDATA[Número 107]]></category>
		<category><![CDATA[Recursos]]></category>
		<category><![CDATA[Webcat]]></category>
		<category><![CDATA[#webcat]]></category>
		<category><![CDATA[diseño web]]></category>
		<category><![CDATA[Navegación]]></category>

		<guid isPermaLink="false">http://mosaic.uoc.edu/?p=13154</guid>
		<description><![CDATA[El WebCat es el punto de encuentro entre profesionales del sector web abierto a cualquier persona interesada en esta parcela. El pasado 13 de febrero tuvo lugar un nuevo encuentro del que a continuación presentamos una breve e interesante muestra. Es la charla de Javier Usobiaga sobre la navegación responsable.]]></description>
				<content:encoded><![CDATA[<p><strong>El WebCat es el punto de encuentro entre profesionales del sector web (desarrolladores, diseñadores, emprendedores, etc.) abierto a cualquier persona interesada en esta parcela.</strong></p>
<p>Dentro de WebCat se abordan asuntos diversos, tanto de forma introductoria como especializada, mediante breves exposiciones de no más de quince minutos con el objetivo de trabajar y transmitir una idea concreta al público.</p>
<p>El pasado 13 de febrero tuvo lugar un nuevo encuentro del que a continuación presentamos una breve e interesante muestra. Es la charla de Javier Usobiaga sobre la navegación responsable.</p>
<h4>Javier Usobiaga &#8211; RWD: dealing with navigation</h4>
<p><iframe src="http://player.vimeo.com/video/62146014" height="281" width="500" allowfullscreen="" frameborder="0"></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://mosaic.uoc.edu/2013/04/24/webcat-rwd-dealing-with-navigation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Processing práctico (Parte 3 de 3)</title>
		<link>http://mosaic.uoc.edu/2013/04/24/processing-practico-parte-3-de-3/</link>
		<comments>http://mosaic.uoc.edu/2013/04/24/processing-practico-parte-3-de-3/#comments</comments>
		<pubDate>Wed, 24 Apr 2013 08:40:03 +0000</pubDate>
		<dc:creator>Mosaic</dc:creator>
				<category><![CDATA[Número 107]]></category>
		<category><![CDATA[Oscar García Pañella]]></category>
		<category><![CDATA[Recursos]]></category>
		<category><![CDATA[animación]]></category>
		<category><![CDATA[interacción]]></category>
		<category><![CDATA[multimedia]]></category>
		<category><![CDATA[Processing]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://mosaic.uoc.edu/?p=13080</guid>
		<description><![CDATA[Tercera y última entrega de tutoriales sobre Processing que nos presenta Oscar García Pañella, Doctor en Realidad Virtual. Processing es un lenguaje de programación de código abierto ideal para gente que quiere crear imágenes, animaciones e interacciones que ha ido evolucionado desde una forma básica hasta convertirse en una herramienta de producción profesional.]]></description>
				<content:encoded><![CDATA[<p><a href="http://processing.org/">Processing</a>&nbsp;se trata de un lenguaje de programación de código abierto ideal para gente que quiere crear imágenes, animaciones e interacciones. Este software ha ido evolucionando a lo largo del tiempo hasta convertirse en una herramienta de producción profesional. Esta es la tercera y definitiva entrega de los tutoriales elaborados por Oscar García Pañella para empezar a trabajar con Processing desde diversas perspectivas:</p>
<p><a href="http://mosaic.uoc.edu/2013/04/24/realidad-aumentada-con-lenguaje-de-programacion-processing/"><strong>Realidad aumentada con lenguaje de programación Processing</strong></a></p>
<p><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/RA.jpg" rel="lightbox[13080]"><img class="alignleft size-medium wp-image-13021" alt="RA" src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/RA-100x75.jpg" width="100" height="75" /></a>Gracias a la Realidad Aumentada podemos añadir elementos sintéticos, clásicamente en 3D, a los ya de por sí reales. Con una cámara y gracias a la ayuda de un patrón que ésta interpretará, posicionaremos un objeto en 3D superpuesto a la imagen de video de nuestra escena.</p>
<p><strong><a href="http://mosaic.uoc.edu/2013/04/24/deteccion-de-colisiones-con-lenguaje-de-programacion-processing/">Detección de colisiones con lenguaje de programación Processing</a></strong></p>
<p><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/coli.jpg" rel="lightbox[13080]"><img class="alignleft size-medium wp-image-13069" alt="coli" src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/coli-81x75.jpg" width="81" height="75" /></a>En este ejemplo vamos a detectar si un objeto que llevamos literalmente “pegado” a nuestro cursor del ratón (un círculo rojo), colisiona con un número aleatorio de otros objetos (varios círculos verdes) dispuestos a lo largo de nuestro canvas. Además informaremos al usuario/a mediante texto de si se está produciendo la colisión o no.&nbsp;</p>
<p><strong><a href="http://mosaic.uoc.edu/2013/04/24/acceso-a-webcam-y-luts-en-programacion-processing/">Acceso a WebCam y LUTs en Programación Processing</a></strong></p>
<p><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/webcam1.jpg" rel="lightbox[13080]"><img class="alignleft size-medium wp-image-13042" alt="webcam1" src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/webcam1-100x71.jpg" width="100" height="71" /></a>Una LUT o “Look Up Table” (ver apartado “Lookup tables in image processing”&nbsp;<a href="http://en.wikipedia.org/wiki/Lookup_table">aquí</a>) es un procedimiento por el cual podemos variar las características (pseudocolorear) de una imagen, sea estática o dinámica como en el caso de una webcam. En definitiva se retocan sus píxeles uno a uno.</p>
<p><strong><a href="http://mosaic.uoc.edu/2013/04/24/acceso-a-webcam-y-procesado-en-programacion-processing/">Acceso a WebCam y procesado en programación Processing</a></strong></p>
<p><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/webcam22.jpg" rel="lightbox[13080]"><img class="alignleft size-medium wp-image-13058" alt="webcam22" src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/webcam22-98x75.jpg" width="98" height="75" /></a>Realizaremos un programa Processing que gracias a la librería Myron nos permitirá disponer de streaming de video en tiempo real vía nuestra webcam, podrá acceder a cada una de las imágenes del streaming y sustituirá los píxeles de la imagen por círculos, discretizándola aún más si cabe. Todo en tiempo real.&nbsp;</p>
<p><strong><a href="http://mosaic.uoc.edu/2013/04/24/operaciones-con-imagenes-en-programacion-processing/">Operaciones con imágenes en programación Processing</a></strong></p>
<p><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/Resta3.jpg" rel="lightbox[13080]"><img class="alignleft size-medium wp-image-13115" alt="Resta" src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/Resta3-100x75.jpg" width="100" height="75" /></a>Una de las operaciones clásicas en la disciplina del&nbsp;<a href="http://es.wikipedia.org/wiki/Retoque_fotogr%C3%A1fico">Procesado de Imagen y del Retoque Fotográfico</a>&nbsp;es la resta de imágenes sucesivas. Es muy útil como primer paso en la detección de, por ejemplo, movimiento en una sala.</p>
]]></content:encoded>
			<wfw:commentRss>http://mosaic.uoc.edu/2013/04/24/processing-practico-parte-3-de-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Operaciones con imágenes en programación Processing</title>
		<link>http://mosaic.uoc.edu/2013/04/24/operaciones-con-imagenes-en-programacion-processing/</link>
		<comments>http://mosaic.uoc.edu/2013/04/24/operaciones-con-imagenes-en-programacion-processing/#comments</comments>
		<pubDate>Wed, 24 Apr 2013 08:16:12 +0000</pubDate>
		<dc:creator>Mosaic</dc:creator>
				<category><![CDATA[Oscar García Pañella]]></category>
		<category><![CDATA[Recursos]]></category>
		<category><![CDATA[multimedia]]></category>
		<category><![CDATA[Processing]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://mosaic.uoc.edu/?p=13026</guid>
		<description><![CDATA[Una de las operaciones clásicas en la disciplina del Procesado de Imagen y del Retoque Fotográfico es la resta de imágenes sucesivas. Es muy útil como primer paso en la detección de, por ejemplo, movimiento en una sala. ]]></description>
				<content:encoded><![CDATA[<p>Una de las operaciones clásicas en la disciplina del <a href="http://es.wikipedia.org/wiki/Retoque_fotogr%C3%A1fico">Procesado de Imagen y del Retoque Fotográfico</a> es la resta de imágenes sucesivas. Es muy útil como primer paso en la detección de, por ejemplo, movimiento en una sala. Imaginemos que tenemos una cámara de video gravando continuamente el mismo plano de la sala. Si nadie entra ni sale todas las imágenes serán exactamente iguales y por lo tanto una resta entre dos cualesquiera dará como resultado una imagen vacía (básicamente negra). Pero ahora imaginemos que, entre una y otra imagen, algo ha variado&#8230;debido a que por ejemplo entró alguien en la sala. Al efectuar la resta observaremos que las diferencias se contrastan y que no obtenemos tan sólo un fondo completamente negro&#8230;y en ese caso podríamos hacer saltar la alarma del banco, del museo o del local a proteger.</p>
<p>En nuestro caso realizaremos un sencillo programa <a href="http://processing.org/">Processing</a> que a) Cargará dos imágenes de disco duro, b) Las restará píxel a píxel y c) El resultado lo almacenará como una tercera imagen que se mostrará también por pantalla. En la figura 1 podemos observarlo claramente.</p>
<p align="center"><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/figura1_2ImagenesQueSeRestan.jpg" rel="lightbox[13026]"><img class="aligncenter size-large wp-image-13027" alt="Restamos las imágenes de arriba para obtener la de debajo. Imágenes cortesía de http://www.freeimageslive.com/." src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/figura1_2ImagenesQueSeRestan-450x355.jpg" width="450" height="355" /></a>&nbsp;</p>
<p align="center"><i>Figura 1. Restamos las imágenes de arriba para obtener la de debajo. Imágenes cortesía de </i><a href="http://www.freeimageslive.com/"><i>http://www.freeimageslive.com/</i></a><i>.</i></p>
<p>Empecemos por aprender cómo se cargan nuestras imágenes en <a href="http://processing.org/">Processing</a>, gracias al código 1.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// Let's load 2 images and generate</li><li>// a third one by substracting them both</li><li>// in a per-pixel basis</li><li>&nbsp;</li><li>// We create 3 PImage objects for our 3 images</li><li>PImage myImage1;</li><li>PImage myImage2;</li><li>PImage myImage3;</li><li>&nbsp;</li><li>// The Setup Function that initializes everything</li><li>void setup(){</li><li>&nbsp;&nbsp;// We setup the window with double dimensions than our images</li><li>&nbsp;&nbsp;// in order to fit them 3 inside the canvas</li><li>&nbsp;&nbsp;size(640, 480);</li><li>&nbsp;&nbsp;// We load the 2 original images into their PImage objects</li><li>&nbsp;&nbsp;myImage1 = loadImage(&quot;image1_to_test_with.jpg&quot;);</li><li>&nbsp;&nbsp;myImage2 = loadImage(&quot;image2_to_test_with.jpg&quot;);</li><li>&nbsp;&nbsp;// The third image is generated with the same dimensions than the 2nd</li><li>&nbsp;&nbsp;// that, by the way, has the same dimensions than the 1st</li><li>&nbsp;&nbsp;myImage3 = createImage(myImage2.width, myImage2.height, RGB);</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 1. Variables, objetos e inicialización de nuestro programa con carga de imágenes incluida.</i></p>
<p>Empezamos creándonos tres objetos Pimage de <a href="http://processing.org/">Processing</a> que serán los encargados de almacenar las imágenes en memoria, previa carga de éstas desde disco duro. Dentro de nuestra función de setup()creamos una ventana de 640 por 480 píxeles para poderlas mostrar todas a la vez. A continuación cargamos las dos imágenes a restar, es decir los ficheros image1_to_test_with.jpg e image2_to_test_with.jpg que previamente habremos introducido en un subdirectorio de nombre “data” dentro del directorio de nuestro sketch <a href="http://processing.org/">Processing</a>. Finalmente tenemos las imágenes cargadas dentro de nuestros objetos myImage. El tercer objeto no lo creamos cargando una imagen sino reservando espacio para acomodar la que surgirá de la resta entre las dos anteriores. Se trata de una imagen <a href="http://es.wikipedia.org/wiki/Modelo_de_color_RGB">RGB</a> con la misma anchura y altura que cualquiera de las dos originales (obtenemos esos datos de la segunda imagen, por ejemplo).</p>
<p>El acceso a cada uno de los píxeles de las imágenes así como la aplicación de la resta en sí se observa dentro de la función draw(), en el código 2.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// The infinite loop</li><li>void draw(){</li><li>&nbsp;&nbsp;// To determine where each pixel is inside the image's array</li><li>&nbsp;&nbsp;int pixelLocation;</li><li>&nbsp;&nbsp;// The new color that we are calculating from the substraction</li><li>&nbsp;&nbsp;color newColor;</li><li>&nbsp;&nbsp;// Accessing pixels in the window implies loading them</li><li>&nbsp;&nbsp;loadPixels(); </li><li>&nbsp;&nbsp;// We also access our test image's pixels</li><li>&nbsp;&nbsp;myImage1.loadPixels();</li><li>&nbsp;&nbsp;myImage2.loadPixels();</li><li>&nbsp;&nbsp;// We loop through all the pixels (#pixels = width x height)</li><li>&nbsp;&nbsp;// We use myImage1 or myImage2 interchangeably because of being equal</li><li>&nbsp;&nbsp;for (int x = 0; x &lt; myImage1.width; x++) {</li><li>&nbsp;&nbsp;&nbsp;&nbsp;for (int y = 0; y &lt; myImage1.height; y++ ) {</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Pixels are located sequentially inside a very long array</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pixelLocation = x + y*myImage1.width;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// The R,G,B values from our 2 images</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float r1 = red(myImage1.pixels[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float g1 = green(myImage1.pixels[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float b1 = blue(myImage1.pixels[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float r2 = red(myImage2.pixels[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float g2 = green(myImage2.pixels[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float b2 = blue(myImage2.pixels[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// We substract pixel by pixel (RGB values): 3rd image = 2nd - 1st</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float r3 = r2 - r1;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float g3 = g2 - g1;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float b3 = b2 - b1;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// We need our components within the 0-255 window</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r3 = constrain(r3,0,255);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g3 = constrain(g3,0,255);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b3 = constrain(b3,0,255);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// We create a new color with our 3 new components</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newColor = color(r3,g3,b3);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// We load the new color into the 3rd image</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myImage3.pixels[pixelLocation] = newColor;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;// Everything needs to be updated with the new values</li><li>&nbsp;&nbsp;updatePixels();</li><li>&nbsp;&nbsp;// We are drawing some yellow text to show captions onto the 3 images</li><li>&nbsp;&nbsp;fill(255,255,0);</li><li>&nbsp;&nbsp;// First image and its text</li><li>&nbsp;&nbsp;image(myImage1,0,0);</li><li>&nbsp;&nbsp;String s = &quot;Original First Image&quot;;</li><li>&nbsp;&nbsp;text(s, 0, 0, 70, 80);&nbsp;&nbsp;// Text wraps within text box</li><li>&nbsp;&nbsp;// Second image and its text</li><li>&nbsp;&nbsp;image(myImage2,320,0);</li><li>&nbsp;&nbsp;s = &quot;Original Second Image&quot;;</li><li>&nbsp;&nbsp;text(s, 320, 0, 70, 80);&nbsp;&nbsp;// Text wraps within text box</li><li>&nbsp;&nbsp;// Third image and its text</li><li>&nbsp;&nbsp;image(myImage3,160,240);</li><li>&nbsp;&nbsp;s = &quot;A third image generated by substracting them both!&quot;;</li><li>&nbsp;&nbsp;text(s, 160, 240, 70, 100);&nbsp;&nbsp;// Text wraps within text box</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 2. Aplicación de la resta entre imágenes.</i></p>
<p>Cuando <a href="http://processing.org/">Processing</a> carga una imagen dentro de un objeto PImage no lo almacena bidimensionalmente, es decir teniendo en cuenta el ancho por el alto, sino que lo hace unidimensionalmente. Se trata en definitiva de un array muy largo donde cada posición almacena el color de un píxel. Lee las sucesivas filas de la imagen y las va concatenando, tal y como podéis observar en el apartado “Pixels, pixels, and more pixels” de <a href="http://processing.org/learning/pixels/">este tutorial</a>. Eso implica que para acceder a un píxel en concreto de nuestra imagen, tenemos que calcular su localización dentro del objeto PImage. Para un píxel que tenga coordenadas XY en la imagen, su ubicación dentro del objeto se calculará como X + Y x Ancho de la Imagen. Y ese valor lo almacenaremos en la variable entera pixelLocation que definimos a tal efecto.</p>
<p>Definimos una variable newColor para guardar el nuevo color que obtendremos de restar los colores de nuestros pares de píxeles y después llamamos a la función de acceso a los píxeles de las imágenes (loadPixels()). A continuación accedemos en concreto a los píxeles de cada una de nuestras dos imágenes de partida.</p>
<p>Hay que recorrer todos los píxeles de la imagen y hay tantos como la resolución de ésta (ancho x alto). Lo haremos con dos estructuras de control de tipo bucle FOR, una dentro de otra, de manera que gracias a la primera iteraremos por columnas (width) y gracias a la segunda por filas (height). Dentro del bucle ya podemos suponer que nos encontramos apuntando a un píxel concreto con coordenadas XY. Calculamos su ubicación dentro del objeto (pixelLocation) y obtenemos los valores de sus tres componentes de color <a href="http://es.wikipedia.org/wiki/Modelo_de_color_RGB">RGB</a> (funciones red, green y blue) para cada imagen. Las asociamos a seis variables de nueva creación (r1, g1 y b1 / r2, g2 y b2). Nótese que éstas son de tipo real y por tanto con decimales (float) dado que las componentes de color se retornan en ese formato.</p>
<p>Llegados a este punto procedemos a obtener el color de la tercera imagen a partir de la resta de colores entre las dos originales. Éste, para cada píxel, se almacena en las variables r3, g3 y b3. Además limitamos las componentes de color que acabamos de calcular a un valor máximo de 255 (si en el cálculo hemos obtenido un número por encima quedará automáticamente recortado) para después crear un nuevo color (newColor) a partir de las variables r3, g3 y b3 que introduciremos en el objeto Pimage de la tercera imagen. Además actualizaremos los píxeles de la imagen a continuación.</p>
<p>Por último tenemos que mostrar las tres imágenes por pantalla y asociarles un texto explicativo en color amarillo (fill(255,255,0)). La primera imagen se carga en la esquina superior izquierda de la ventana (image(myImage1,0,0)) mientras que la segunda se muestra desplazada horizontalmente a partir de la mitad de la ventana (image(myImage2,320,0)). La tercera se mostrará debajo de ambas, centrada (image(myImage3,160,240)). En los tres casos modificaremos el texto a introducir dentro de la variable de tipo string s para que se adapte a cada situación. Todo gracias a la función text() de <a href="http://processing.org/">Processing</a> que recibe como parámetros la cadena de texto a mostrar por pantalla así como las dimensiones de la caja de texto que la contiene.</p>
<p>El programa completo podéis observarlo en el código 4 y os invito a que lo modifiquéis a conveniencia para obtener resultados de todo tipo.</p>
<p></code><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// Let's load 2 images and generate</li><li>// a third one by substracting them both</li><li>// in a per-pixel basis</li><li>&nbsp;</li><li>// We create 3 PImage objects for our 3 images</li><li>PImage myImage1;</li><li>PImage myImage2;</li><li>PImage myImage3;</li><li>&nbsp;</li><li>// The Setup Function that initializes everything</li><li>void setup(){</li><li>&nbsp;&nbsp;// We setup the window with double dimensions than our images</li><li>&nbsp;&nbsp;// in order to fit them 3 inside the canvas</li><li>&nbsp;&nbsp;size(640, 480);</li><li>&nbsp;&nbsp;// We load the 2 original images into their PImage objects</li><li>&nbsp;&nbsp;myImage1 = loadImage(&quot;image1_to_test_with.jpg&quot;);</li><li>&nbsp;&nbsp;myImage2 = loadImage(&quot;image2_to_test_with.jpg&quot;);</li><li>&nbsp;&nbsp;// The third image is generated with the same dimensions than the 2nd</li><li>&nbsp;&nbsp;// that, by the way, has the same dimensions than the 1st</li><li>&nbsp;&nbsp;myImage3 = createImage(myImage2.width, myImage2.height, RGB);</li><li>}</li><li>&nbsp;</li><li>// The infinite loop</li><li>void draw(){</li><li>&nbsp;&nbsp;// To determine where each pixel is inside the image's array</li><li>&nbsp;&nbsp;int pixelLocation;</li><li>&nbsp;&nbsp;// The new color that we are calculating from the substraction</li><li>&nbsp;&nbsp;color newColor;</li><li>&nbsp;&nbsp;// Accessing pixels in the window implies loading them</li><li>&nbsp;&nbsp;loadPixels(); </li><li>&nbsp;&nbsp;// We also access our test image's pixels</li><li>&nbsp;&nbsp;myImage1.loadPixels();</li><li>&nbsp;&nbsp;myImage2.loadPixels();</li><li>&nbsp;&nbsp;// We loop through all the pixels (#pixels = width x height)</li><li>&nbsp;&nbsp;// We use myImage1 or myImage2 interchangeably because of being equal</li><li>&nbsp;&nbsp;for (int x = 0; x &lt; myImage1.width; x++) {</li><li>&nbsp;&nbsp;&nbsp;&nbsp;for (int y = 0; y &lt; myImage1.height; y++ ) {</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Pixels are located sequentially inside a very long array</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pixelLocation = x + y*myImage1.width;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// The R,G,B values from our 2 images</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float r1 = red(myImage1.pixels[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float g1 = green(myImage1.pixels[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float b1 = blue(myImage1.pixels[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float r2 = red(myImage2.pixels[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float g2 = green(myImage2.pixels[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float b2 = blue(myImage2.pixels[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// We substract pixel by pixel (RGB values): 3rd image = 2nd - 1st</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float r3 = r2 - r1;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float g3 = g2 - g1;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float b3 = b2 - b1;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// We need our components within the 0-255 window</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r3 = constrain(r3,0,255);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g3 = constrain(g3,0,255);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b3 = constrain(b3,0,255);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// We create a new color with our 3 new components</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newColor = color(r3,g3,b3);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// We load the new color into the 3rd image</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myImage3.pixels[pixelLocation] = newColor;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;// Everything needs to be updated with the new values</li><li>&nbsp;&nbsp;updatePixels();</li><li>&nbsp;&nbsp;// We are drawing some yellow text to show captions onto the 3 images</li><li>&nbsp;&nbsp;fill(255,255,0);</li><li>&nbsp;&nbsp;// First image and its text</li><li>&nbsp;&nbsp;image(myImage1,0,0);</li><li>&nbsp;&nbsp;String s = &quot;Original First Image&quot;;</li><li>&nbsp;&nbsp;text(s, 0, 0, 70, 80);&nbsp;&nbsp;// Text wraps within text box</li><li>&nbsp;&nbsp;// Second image and its text</li><li>&nbsp;&nbsp;image(myImage2,320,0);</li><li>&nbsp;&nbsp;s = &quot;Original Second Image&quot;;</li><li>&nbsp;&nbsp;text(s, 320, 0, 70, 80);&nbsp;&nbsp;// Text wraps within text box</li><li>&nbsp;&nbsp;// Third image and its text</li><li>&nbsp;&nbsp;image(myImage3,160,240);</li><li>&nbsp;&nbsp;s = &quot;A third image generated by substracting them both!&quot;;</li><li>&nbsp;&nbsp;text(s, 160, 240, 70, 100);&nbsp;&nbsp;// Text wraps within text box</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 4. Programa completo de resta de imágenes.</i></p>
<p>&nbsp;</code></p>
]]></content:encoded>
			<wfw:commentRss>http://mosaic.uoc.edu/2013/04/24/operaciones-con-imagenes-en-programacion-processing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Acceso a WebCam y procesado en programación Processing</title>
		<link>http://mosaic.uoc.edu/2013/04/24/acceso-a-webcam-y-procesado-en-programacion-processing/</link>
		<comments>http://mosaic.uoc.edu/2013/04/24/acceso-a-webcam-y-procesado-en-programacion-processing/#comments</comments>
		<pubDate>Wed, 24 Apr 2013 08:11:34 +0000</pubDate>
		<dc:creator>Mosaic</dc:creator>
				<category><![CDATA[Oscar García Pañella]]></category>
		<category><![CDATA[Recursos]]></category>
		<category><![CDATA[imagen]]></category>
		<category><![CDATA[multimedia]]></category>
		<category><![CDATA[Processing]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://mosaic.uoc.edu/?p=13049</guid>
		<description><![CDATA[Realizaremos un programa Processing que gracias a la librería Myron nos permitirá disponer de streaming de video en tiempo real vía nuestra webcam, podrá acceder a cada una de las imágenes del streaming y sustituirá los píxeles de la imagen por círculos, discretizándola aún más si cabe. Todo en tiempo real. ]]></description>
				<content:encoded><![CDATA[<p>Realizaremos un programa <a href="http://processing.org/">Processing</a> que gracias a la <a href="http://webcamxtra.sourceforge.net/">librería Myron</a> a) Nos permitirá disponer de streaming de video en tiempo real vía nuestra webcam, b) Podrá acceder a cada una de las imágenes del streaming y c) Sustituirá los píxeles de la imagen por círculos, discretizándola aún más si cabe. Todo en tiempo real. Algo parecido, dependiendo del radio de éstos, al efecto de “Pointillism” o <a href="http://es.wikipedia.org/wiki/Puntillismo">Puntillismo</a>. En la figura 1 podemos observarlo.</p>
<p align="center">&nbsp;<a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/webcam2.png" rel="lightbox[13049]"><img class="aligncenter size-large wp-image-13050" alt="webcam2" src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/webcam2-450x301.png" width="450" height="301" /></a></p>
<p align="center"><i>Figura 1. Diferentes resoluciones de discretización de nuestras imágenes de vídeo.</i></p>
<p>Es importante tener en cuenta que para asegurar el correcto funcionamiento de la <a href="http://webcamxtra.sourceforge.net/">librería Myron</a> de acceso a webcam y reproducción de video, tenemos que colocar los ficheros <a href="http://es.wikipedia.org/wiki/Dll">.DLL</a> que la conforman dentro del directorio <a href="http://processing.org/">Processing</a> de nuestro ordenador. Se trata de los ficheros DSVL.dll y myron_ezcam.dll.</p>
<p>Empecemos por aprender cómo se carga video, gracias al código 1.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// We will access our webcam</li><li>// thanks to the Myron library</li><li>// available at http://webcamxtra.sourceforge.net/</li><li>// Therefore we import it</li><li>import JMyron.*;</li><li>// We create a JMyron object to manage the video streaming</li><li>// that comes from our webcam</li><li>JMyron myStream;</li><li>&nbsp;</li><li>// Our setup function to be executed once we begin</li><li>void setup(){</li><li>&nbsp;&nbsp;// The size of our canvas equals the optimal resolution</li><li>&nbsp;&nbsp;// of our webcam (check out yours to avoid flickering!)</li><li>&nbsp;&nbsp;size(640, 400);</li><li>&nbsp;&nbsp;// We initialize the myStream object</li><li>&nbsp;&nbsp;// and we start streaming from our webcam</li><li>&nbsp;&nbsp;myStream = new JMyron();</li><li>&nbsp;&nbsp;myStream.start(width, height);</li><li>&nbsp;&nbsp;// No strokes for our little circular objects</li><li>&nbsp;&nbsp;noStroke();</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 1. Inicialización de la carga de video en nuestro programa.</i></p>
<p>Empezamos importando la <a href="http://webcamxtra.sourceforge.net/">librería Myron</a> para poder acceder a sus funciones mediante la sentencia import JMyron.* y creamos un objeto de tipo JMyron que dará soporte a nuestro streaming de video por parte de la webcam (myStream). La función de inicialización setup() crea una ventana de 640 x 400 píxeles porque esa es la resolución de trabajo óptima para la webcam que se ha utilizado para programar este ejemplo por mi parte. Es importante que para vuestro caso concreto os informéis sobre la resolución óptima de vuestro periférico y actuéis en consecuencia. En caso contrario podríais estar trabajando con resoluciones forzadas o no admitidas que inestabilizarían el programa y podrían causar problemas de “flickering” (parpadeo)&nbsp; como se nos comenta <a href="http://mrl.nyu.edu/~perlin/courses/fall2006mm/using-jmyron.html">aquí</a>.</p>
<p>Inicializamos nuestro objeto de video myStream y a continuación avisamos al sistema de que puede iniciarse la adquisición de video por parte de la webcam (myStream.start(width, height)) a una resolución idéntica a la definida para nuestra ventana (el video la ocupará por entero). Por último desactivamos el color para los bordes (noStroke()).</p>
<p>El acceso a cada uno de los píxeles de las imágenes sucesivas así como la aplicación del efecto de discretización se observa dentro de la función draw(), en el código 2.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// the infinite loop</li><li>void draw(){</li><li>&nbsp;&nbsp;// We ask our myStream object to provide with a new frame</li><li>&nbsp;&nbsp;myStream.update();</li><li>&nbsp;&nbsp;// We define some variables.</li><li>&nbsp;&nbsp;// Note that we store the current webcam image inside an array called frameArray</li><li>&nbsp;&nbsp;int[] frameArray = myStream.image();</li><li>&nbsp;&nbsp;int pixelLocation;</li><li>&nbsp;&nbsp;float r,g,b;</li><li>&nbsp;&nbsp;int ellipseMagnitude = 15;</li><li>&nbsp;</li><li>&nbsp;&nbsp;// We loop all over the pixels inside the captured image</li><li>&nbsp;&nbsp;for (int y=0; y &lt; height; y+=15){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;for (int x=0; x &lt; width; x+=15){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Evaluating the 2D coordinates of the current pixel</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pixelLocation = x + y*width;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Retrieving the RGB color of the current pixel</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r = red(frameArray[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g = green(frameArray[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b = blue(frameArray[pixelLocation]); </li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// We will substitute the current pixel</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// by a circle (same color)</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ellipseMagnitude controls the magnitude of the circle</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fill(r,g,b,150);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ellipse(x,y,ellipseMagnitude,ellipseMagnitude);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;}</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 2. Aplicación del efecto de discretización a nuestras imágenes de video.</i></p>
<p>Iniciamos actualizando el streaming de video, es decir “pidiendo” una nueva imagen (myStream.update()) que almacenamos convenientemente en un array de enteros que declaramos a tal efecto (int[] frameArray = myStream.image()). Además, definimos tres variables reales, es decir que contendrán datos numéricos con decimales, para almacenar las componentes <a href="http://es.wikipedia.org/wiki/Modelo_de_color_RGB">RGB</a> de cada uno de los píxeles que modifiquemos (float r,g,b) y el diámetro que deseamos para nuestros círculos (ellipseMagnitude). &nbsp;Es importante tener en cuenta que cuando <a href="http://processing.org/">Processing</a> carga una imagen no la almacena bidimensionalmente, es decir teniendo en cuenta el ancho por el alto, sino que lo hace unidimensionalmente. Se trata en definitiva de un array muy largo donde cada posición almacena el color de un píxel. Lee las sucesivas filas de la imagen y las va concatenando, tal y como podéis observar en el apartado “Pixels, pixels, and more pixels” de <a href="http://processing.org/learning/pixels/">este tutorial</a>. Eso implica que para acceder a un píxel en concreto de nuestra imagen, tenemos que calcular su localización dentro del objeto. En este ejemplo necesitamos asociar un círculo a la ubicación física de cada pixel y por tanto tendremos esto en cuenta. Para un píxel que tenga coordenadas XY en la imagen, su ubicación dentro del objeto se calculará como X + Y x Ancho de la Imagen. Y ese valor lo almacenaremos en la variable entera pixelLocation que definimos a tal efecto.</p>
<p>Hay que recorrer todos los píxeles de la imagen y hay tantos como la resolución de ésta (ancho x alto). Lo haremos con dos estructuras de control de tipo bucle FOR, una dentro de otra, de manera que gracias a la primera iteraremos por columnas (width) y gracias a la segunda por filas (height). Dentro del bucle ya podemos suponer que nos encontramos apuntando a un píxel concreto con coordenadas XY. Calculamos su ubicación dentro del objeto (pixelLocation) y obtenemos los valores de sus tres componentes de color <a href="http://es.wikipedia.org/wiki/Modelo_de_color_RGB">RGB</a> (funciones red, green y blue) para asociarlas a tres variables de nueva creación (r, g y b). Nótese que éstas son de tipo real y por tanto con decimales (float) dado que las componentes de color se retornan en ese formato.</p>
<p>Llegados a este punto sólo nos queda fijar un círculo del mismo color que el píxel que se encuentra debajo y que actuará como su centro. Activamos el color de nuestro círculo gracias a la función fill(r,g,b,150) y lo pintamos. El círculo tiene una cierta transparencia, como puede observarse en el cuarto parámetro de la función fill(), que hace referencia al <a href="http://en.wikipedia.org/wiki/Alpha_compositing">canal alfa</a>.</p>
<p>Por último y como observamos en el código 3, creamos una función pública que es obligatoria para el buen funcionamiento de la <a href="http://webcamxtra.sourceforge.net/">librería Myron</a> (public void stop()). Ésta se ejecutará al salir del programa y en ella se detienen tanto la trama de vídeo que se está generando vía nuestro objeto (myStream.stop()) como el proceso en sí (super.stop()).</p>
<p>A continuación se muestran los códigos 3, al que nos referíamos en el último párrafo, así como el código 4 que contiene todo el programa funcional.</p>
<p></code><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// The Myron library demands for a specific method to stop</li><li>public void stop() {</li><li>&nbsp;&nbsp;myStream.stop();</li><li>&nbsp;&nbsp;super.stop();</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 3. Método de parada de la librería.</i></p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// We will access our webcam</li><li>// thanks to the Myron library</li><li>// available at http://webcamxtra.sourceforge.net/</li><li>// Therefore we import it</li><li>import JMyron.*;</li><li>// We create a JMyron object to manage the video streaming</li><li>// that comes from our webcam</li><li>JMyron myStream;</li><li>&nbsp;</li><li>// Our setup function to be executed once we begin</li><li>void setup(){</li><li>&nbsp;&nbsp;// The size of our canvas equals the optimal resolution</li><li>&nbsp;&nbsp;// of our webcam (check out yours to avoid flickering!)</li><li>&nbsp;&nbsp;size(640, 400);</li><li>&nbsp;&nbsp;// We initialize the myStream object</li><li>&nbsp;&nbsp;// and we start streaming from our webcam</li><li>&nbsp;&nbsp;myStream = new JMyron();</li><li>&nbsp;&nbsp;myStream.start(width, height);</li><li>&nbsp;&nbsp;// No strokes for our little circular objects</li><li>&nbsp;&nbsp;noStroke();</li><li>}</li><li>&nbsp;</li><li>// the infinite loop</li><li>void draw(){</li><li>&nbsp;&nbsp;// We ask our myStream object to provide with a new frame</li><li>&nbsp;&nbsp;myStream.update();</li><li>&nbsp;&nbsp;// We define some variables.</li><li>&nbsp;&nbsp;// Note that we store the current webcam image inside an array called frameArray</li><li>&nbsp;&nbsp;int[] frameArray = myStream.image();</li><li>&nbsp;&nbsp;int pixelLocation;</li><li>&nbsp;&nbsp;float r,g,b;</li><li>&nbsp;&nbsp;int ellipseMagnitude = 15;</li><li>&nbsp;</li><li>&nbsp;&nbsp;// We loop all over the pixels inside the captured image</li><li>&nbsp;&nbsp;for (int y=0; y &lt; height; y+=15){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;for (int x=0; x &lt; width; x+=15){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Evaluating the 2D coordinates of the current pixel</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pixelLocation = x + y*width;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Retrieving the RGB color of the current pixel</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r = red(frameArray[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g = green(frameArray[pixelLocation]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b = blue(frameArray[pixelLocation]); </li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// We will substitute the current pixel</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// by a circle (same color)</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ellipseMagnitude controls the magnitude of the circle</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fill(r,g,b,150);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ellipse(x,y,ellipseMagnitude,ellipseMagnitude);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;}</li><li>}</li><li>&nbsp;</li><li>// The Myron library demands for a specific method to stop</li><li>public void stop() {</li><li>&nbsp;&nbsp;myStream.stop();</li><li>&nbsp;&nbsp;super.stop();</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 4. Programa completo de aplicación de discretización </i>a<i> nuestras imágenes de vídeo.</i></p>
<p>&nbsp;</code></p>
]]></content:encoded>
			<wfw:commentRss>http://mosaic.uoc.edu/2013/04/24/acceso-a-webcam-y-procesado-en-programacion-processing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Acceso a WebCam y LUTs en Programación Processing</title>
		<link>http://mosaic.uoc.edu/2013/04/24/acceso-a-webcam-y-luts-en-programacion-processing/</link>
		<comments>http://mosaic.uoc.edu/2013/04/24/acceso-a-webcam-y-luts-en-programacion-processing/#comments</comments>
		<pubDate>Wed, 24 Apr 2013 08:06:25 +0000</pubDate>
		<dc:creator>Mosaic</dc:creator>
				<category><![CDATA[Oscar García Pañella]]></category>
		<category><![CDATA[Recursos]]></category>
		<category><![CDATA[animación]]></category>
		<category><![CDATA[imagen]]></category>
		<category><![CDATA[multimedia]]></category>
		<category><![CDATA[Processing]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://mosaic.uoc.edu/?p=13038</guid>
		<description><![CDATA[Una LUT o “Look Up Table” es un procedimiento por el cual podemos variar las características (pseudocolorear) de una imagen, sea estática o dinámica como en el caso de una webcam. En definitiva se retocan sus píxeles uno a uno.]]></description>
				<content:encoded><![CDATA[<p>Una LUT o “Look Up Table” (ver apartado “Lookup tables in image processing” <a href="http://en.wikipedia.org/wiki/Lookup_table">aquí</a>) es un procedimiento por el cual podemos variar las características (pseudocolorear) de una imagen, sea estática o dinámica como en el caso de una webcam. En definitiva se retocan sus píxeles uno a uno. Se trata de recorrerlos todos, obtener su valor y, precisamente en base a la <a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a> que diseñemos, retocarlo de manera que pase a ser diferente. Las <a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a>s se utilizan en todos los programas de edición y retoque fotográfico e incluso en algunas cámaras digitales para aplicar filtros a nuestras imágenes: pasarla de color a blanco y negro, pasarla a tono sepia, variar su brillo, etc. También se han empleado para “colorear” películas que originalmente se filmaron en blanco y negro o para aplicar tonalidades de colores distintas en mapas del tiempo y en función de la temperatura (rojo para el calor, verde para zonas neutras y azul para el frío).</p>
<p>En nuestro caso realizaremos un programa <a href="http://processing.org/">Processing</a> que gracias a la <a href="http://webcamxtra.sourceforge.net/">librería Myron</a> a) Nos permitirá disponer de streaming de video en tiempo real vía nuestra webcam, b) Podrá acceder a cada una de las imágenes del streaming y c) Aplicará una <a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a> sobre ellas que además variará en función de la tecla que hayamos pulsado (0, 1, 2, 3 o 4). En la figura 1 podemos entenderlo mejor.</p>
<p><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/webcam.png" rel="lightbox[13038]"><img class="aligncenter size-large wp-image-13040" alt="webcam" src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/webcam-450x320.png" width="450" height="320" /></a></p>
<p align="center"><i>Figura 1. Dependiendo de qué tecla pulsemos obtendremos diferentes efectos en nuestro streaming de video. De izquierda a derecha se muestran los efectos: original, inversión de rojos y </i><a href="http://es.wikipedia.org/wiki/Ruido_blanco"><i>ruido blanco</i></a><i> aleatorio.</i></p>
<p>Las opciones de que disponemos son:</p>
<ul>
<li><b>Pulsando la tecla 0</b>: volver a la imagen de video original.</li>
<li><b>Pulsando la tecla 1</b>: <a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a> que enfatiza los tonos rojos y “cyan”.</li>
<li><b>Pulsando la tecla 2</b>: <a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a> que enfatiza los tonos verdes extremos y lilas.</li>
<li><b>Pulsando la tecla 3</b>: <a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a> que enfatiza los tonos azules y amarillos.</li>
<li><b>Pulsando la tecla 4</b>: generamos una imagen en movimiento de <a href="http://es.wikipedia.org/wiki/Ruido_blanco">ruido blanco</a> aleatorio (como cuando en un televisor no tenemos un canal correctamente sintonizado).</li>
</ul>
<p>Es importante tener en cuenta que para asegurar el correcto funcionamiento de la <a href="http://webcamxtra.sourceforge.net/">librería Myron</a> de acceso a webcam y reproducción de video, tenemos que colocar los ficheros <a href="http://es.wikipedia.org/wiki/Dll">.DLL</a> que la conforman dentro del directorio <a href="http://processing.org/">Processing</a> de nuestro ordenador. Se trata de los ficheros DSVL.dll y myron_ezcam.dll.</p>
<p>Empecemos por aprender cómo se carga video, gracias al código 1.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// We will access our webcam</li><li>// thanks to the Myron library</li><li>// available at http://webcamxtra.sourceforge.net/</li><li>// Therefore we import it</li><li>import JMyron.*;</li><li>// We create a JMyron object to manage the video streaming</li><li>// that comes from our webcam</li><li>JMyron myStream;</li><li>// We define a mode variable to control</li><li>// the video rendering from 5 possibilities</li><li>// mode can be 0,1,2,3 or 4</li><li>int mode = 0;</li><li>&nbsp;</li><li>// Our setup function to be executed once we begin</li><li>void setup() {</li><li>&nbsp;&nbsp;// The sizw of our canvas equals the optimal resolution</li><li>&nbsp;&nbsp;// of our webcam (check out yours to avoid flickering!)</li><li>&nbsp;&nbsp;size(640, 400);</li><li>&nbsp;&nbsp;// We initialize the myStream object</li><li>&nbsp;&nbsp;// and we start streaming from our webcam</li><li>&nbsp;&nbsp;myStream = new JMyron();</li><li>&nbsp;&nbsp;myStream.start(width, height);</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 1. Inicialización de la carga de video en nuestro programa.</i></p>
<p>Por una parte creamos una variable para controlar cual de las dos <a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a>s queremos aplicar (mode). Además importamos la <a href="http://webcamxtra.sourceforge.net/">librería Myron</a> para poder acceder a sus funciones mediante la sentencia import JMyron.* y creamos un objeto de tipo JMyron que dará soporte a nuestro streaming de video por parte de la webcam (myStream). La función de inicialización setup() crea una ventana de 640 x 400 píxeles porque esa es la resolución de trabajo óptima para la webcam que se ha utilizado para programar este ejemplo por mi parte. Es importante que para vuestro caso concreto os informéis sobre la resolución óptima de vuestro periférico y actuéis en consecuencia. En caso contrario podríais estar trabajando con resoluciones forzadas o no admitidas que inestabilizarían el programa y podrían causar problemas de “flickering” (parpadeo)&nbsp; como se nos comenta <a href="http://mrl.nyu.edu/~perlin/courses/fall2006mm/using-jmyron.html">aquí</a>.</p>
<p>Inicializamos nuestro objeto de video myStream y a continuación avisamos al sistema de que puede iniciarse la adquisición de video por parte de la webcam (myStream.start(width, height)) a una resolución idéntica a la definida para nuestra ventana (el video la ocupará por entero).</p>
<p>El acceso a cada uno de los píxeles de las imágenes sucesivas así como la aplicación de las distintas &nbsp;<a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a>s se observa dentro de la función draw(), en el código 2.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// the infinite loop</li><li>void draw() {</li><li>&nbsp;&nbsp;// We ask our myStream object to provide with a new frame</li><li>&nbsp;&nbsp;myStream.update();</li><li>&nbsp;&nbsp;// We get the actual frame and copy it into an array (frameArray)</li><li>&nbsp;&nbsp;int[] frameArray = myStream.image();</li><li>&nbsp;&nbsp;// We will need to access the RGB properties of every pixel in frameArray</li><li>&nbsp;&nbsp;float r,g,b;</li><li>&nbsp;&nbsp;// We draw the pixels for the current frame to the screen</li><li>&nbsp;&nbsp;loadPixels();</li><li>&nbsp;&nbsp;// We loop all over our frameArray</li><li>&nbsp;&nbsp;for (int i = 0; i &lt; width*height; i++){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// For every pixel, we get its RGB components</li><li>&nbsp;&nbsp;&nbsp;&nbsp;r = red(frameArray[i]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;g = green(frameArray[i]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;b = blue(frameArray[i]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// Now it's time to apply our special effects menu</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// 5 different modes (0,1,2,3 and 4)</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// 0 = original image</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// 1 = inverting the red component</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// 2 = inverting the green component</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// 3 = inverting the blue component</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// 4 = a random image! unrelated to the one coming from the webcam</li><li>&nbsp;&nbsp;&nbsp;&nbsp;if (mode == 1) r = 255 - r;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;else if (mode == 2) g = 255 - g;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;else if (mode == 3) b = 255 - b;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;else if (mode == 4){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r = random(255);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g = random(255);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b = random(255);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// We save our pseudocolored image</li><li>&nbsp;&nbsp;&nbsp;&nbsp;pixels[i] = color(r,g,b);</li><li>&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;// We update the image to appear in the canvas</li><li>&nbsp;&nbsp;updatePixels();</li><li>&nbsp;&nbsp;// Some white text to inform user about switching between modes</li><li>&nbsp;&nbsp;String s = &quot;Toggle rendering modes by pressing 0,1,2,3 or 4&quot;;</li><li>&nbsp;&nbsp;fill(255);</li><li>&nbsp;&nbsp;text(s, 10, 370, 200, 40);</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 2. Aplicación de las </i><a href="http://en.wikipedia.org/wiki/Lookup_table"><i>LUT</i></a><i>s a nuestras imágenes de video.</i></p>
<p>Iniciamos actualizando el streaming de video, es decir “pidiendo” una nueva imagen (myStream.update()) que almacenamos convenientemente en un array de enteros que declaramos a tal efecto (int[] frameArray = myStream.image()). Además, definimos tres variables reales, es decir que contendrán datos numéricos con decimales, para almacenar las componentes <a href="http://es.wikipedia.org/wiki/Modelo_de_color_RGB">RGB</a> de cada uno de los píxeles que modifiquemos (float r,g,b) y cargamos los píxeles de la imagen a memoria para poderlos acceder (loadPixels()). &nbsp;Es importante tener en cuenta que cuando <a href="http://processing.org/">Processing</a> carga una imagen no la almacena bidimensionalmente, es decir teniendo en cuenta el ancho por el alto, sino que lo hace unidimensionalmente. Se trata en definitiva de un array muy largo donde cada posición almacena el color de un píxel. Lee las sucesivas filas de la imagen y las va concatenando, tal y como podéis observar en el apartado “Pixels, pixels, and more pixels” de <a href="http://processing.org/learning/pixels/">este tutorial</a>. Eso implica que para acceder a un píxel en concreto de nuestra imagen, tenemos que calcular su localización dentro del objeto PImage. De todas formas en nuestro caso iteraremos a lo largo de todo el array frameArray y aplicaremos la misma condición a cada píxel. Iteramos vía una estructura de control de bucle tipo FOR que recorre todo el largo del array. Su dimensión iguala a la resolución de la imagen, es decir su ancho por su alto (width*height). Una vez dentro del bucle podemos considerar que estamos iterando píxel a píxel. Obtenemos sus componentes de color <a href="http://es.wikipedia.org/wiki/Modelo_de_color_RGB">RGB</a> (r = red(frameArray[i]), g = green(frameArray[i]) y b = blue(frameArray[i])) y dependiendo del modo activo (mode) aplicamos una u otra <a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a>, gracias a un condicional de tipo IF:</p>
<ul>
<li><b>Si se pulsó la tecla 0</b>: no hacemos nada dado que deseamos mantener o volver a la imagen de video original.</li>
<li><b>Si se pulsó la tecla 1</b>: invertimos el canal rojo (r = 255 &#8211; r) para nuestra <a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a> que enfatiza los tonos rojos y “cyan”.</li>
<li><b>Si se pulsó la tecla 2</b>: invertimos el canal verde (g = 255 &#8211; g) para nuestra <a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a> que enfatiza los tonos verdes extremos y lilas.</li>
<li><b>Si se pulsó la tecla 3</b>: invertimos el canal azul (g = 255 &#8211; g) para nuestra <a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a> que enfatiza los tonos azules y amarillos.</li>
<li><b>Si se pulsó la tecla 4</b>: generamos componentes aleatorias para nuestro píxel gracias a la función random.</li>
</ul>
<p>Hecho esto salvamos el “nuevo” píxel a partir de un color que generamos con las tres componentes (pixels[i] = color(r,g,b)). Una vez se recorre toda la imagen, terminamos el bucle y actualizamos todos los píxeles a la imagen para después mostrar un texto informativo en color blanco (fill(255)) y gracias a la función text().</p>
<p>Por último y como observamos en el código 3, hacemos dos cosas:</p>
<ol>
<li>Creamos una función pública que es obligatoria para el buen funcionamiento de la <a href="http://webcamxtra.sourceforge.net/">librería Myron</a> (public void stop()). Ésta se ejecutará al salir del programa y en ella se detienen tanto la trama de vídeo que se está generando vía nuestro objeto (myStream.stop()) como el proceso en sí (super.stop()).</li>
<li>Mediante el evento/callback de teclas de <a href="http://processing.org/">Processing</a> (keyPressed()), detectamos aquella que presiona el usuario y actualizamos la variable mode en consecuencia.</li>
</ol>
<p>A continuación se muestran los códigos 3, al que nos referíamos en el último párrafo, así como el código 4 que contiene todo el programa funcional.</p>
<p></code><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// The Myron library demands for a specific method to stop</li><li>public void stop() {</li><li>&nbsp;&nbsp;myStream.stop();</li><li>&nbsp;&nbsp;super.stop();</li><li>}</li><li>&nbsp;</li><li>// We toggle between modes depending on the pressed key</li><li>void keyPressed(){</li><li>&nbsp;&nbsp;if (key == '0') mode = 0;</li><li>&nbsp;&nbsp;if (key == '1') mode = 1;</li><li>&nbsp;&nbsp;if (key == '2') mode = 2; </li><li>&nbsp;&nbsp;if (key == '3') mode = 3;</li><li>&nbsp;&nbsp;if (key == '4') mode = 4;</li><li>}</li><li>Código 3. Método de parada de la librería y gestión de teclado.</li><li>// We will access our webcam</li><li>// thanks to the Myron library</li><li>// available at http://webcamxtra.sourceforge.net/</li><li>// Therefore we import it</li><li>import JMyron.*;</li><li>// We create a JMyron object to manage the video streaming</li><li>// that comes from our webcam</li><li>JMyron myStream;</li><li>// We define a mode variable to control</li><li>// the video rendering from 5 possibilities</li><li>// mode can be 0,1,2,3 or 4</li><li>int mode = 0;</li><li>&nbsp;</li><li>// Our setup function to be executed once we begin</li><li>void setup() {</li><li>&nbsp;&nbsp;// The sizw of our canvas equals the optimal resolution</li><li>&nbsp;&nbsp;// of our webcam (check out yours to avoid flickering!)</li><li>&nbsp;&nbsp;size(640, 400);</li><li>&nbsp;&nbsp;// We initialize the myStream object</li><li>&nbsp;&nbsp;// and we start streaming from our webcam</li><li>&nbsp;&nbsp;myStream = new JMyron();</li><li>&nbsp;&nbsp;myStream.start(width, height);</li><li>}</li><li>&nbsp;</li><li>// the infinite loop</li><li>void draw() {</li><li>&nbsp;&nbsp;// We ask our myStream object to provide with a new frame</li><li>&nbsp;&nbsp;myStream.update();</li><li>&nbsp;&nbsp;// We get the actual frame and copy it into an array (frameArray)</li><li>&nbsp;&nbsp;int[] frameArray = myStream.image();</li><li>&nbsp;&nbsp;// We will need to access the RGB properties of every pixel in frameArray</li><li>&nbsp;&nbsp;float r,g,b;</li><li>&nbsp;&nbsp;// We draw the pixels for the current frame to the screen</li><li>&nbsp;&nbsp;loadPixels();</li><li>&nbsp;&nbsp;// We loop all over our frameArray</li><li>&nbsp;&nbsp;for (int i = 0; i &lt; width*height; i++){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// For every pixel, we get its RGB components</li><li>&nbsp;&nbsp;&nbsp;&nbsp;r = red(frameArray[i]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;g = green(frameArray[i]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;b = blue(frameArray[i]);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// Now it's time to apply our special effects menu</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// 5 different modes (0,1,2,3 and 4)</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// 0 = original image</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// 1 = inverting the red component</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// 2 = inverting the green component</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// 3 = inverting the blue component</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// 4 = a random image! unrelated to the one coming from the webcam</li><li>&nbsp;&nbsp;&nbsp;&nbsp;if (mode == 1) r = 255 - r;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;else if (mode == 2) g = 255 - g;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;else if (mode == 3) b = 255 - b;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;else if (mode == 4){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r = random(255);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g = random(255);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b = random(255);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// We save our pseudocolored image</li><li>&nbsp;&nbsp;&nbsp;&nbsp;pixels[i] = color(r,g,b);</li><li>&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;// We update the image to appear in the canvas</li><li>&nbsp;&nbsp;updatePixels();</li><li>&nbsp;&nbsp;// Some white text to inform user about switching between modes</li><li>&nbsp;&nbsp;String s = &quot;Toggle rendering modes by pressing 0,1,2,3 or 4&quot;;</li><li>&nbsp;&nbsp;fill(255);</li><li>&nbsp;&nbsp;text(s, 10, 370, 200, 40);</li><li>}</li><li>&nbsp;</li><li>// The Myron library demands for a specific method to stop</li><li>public void stop() {</li><li>&nbsp;&nbsp;myStream.stop();</li><li>&nbsp;&nbsp;super.stop();</li><li>}</li><li>&nbsp;</li><li>// We toggle between modes depending on the pressed key</li><li>void keyPressed(){</li><li>&nbsp;&nbsp;if (key == '0') mode = 0;</li><li>&nbsp;&nbsp;if (key == '1') mode = 1;</li><li>&nbsp;&nbsp;if (key == '2') mode = 2; </li><li>&nbsp;&nbsp;if (key == '3') mode = 3;</li><li>&nbsp;&nbsp;if (key == '4') mode = 4;</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 4. Programa completo de aplicación de </i><a href="http://en.wikipedia.org/wiki/Lookup_table"><i>LUT</i></a><i>s en nuestras imágenes de vídeo.</i></p>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://mosaic.uoc.edu/2013/04/24/acceso-a-webcam-y-luts-en-programacion-processing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Detección de colisiones con lenguaje de programación Processing</title>
		<link>http://mosaic.uoc.edu/2013/04/24/deteccion-de-colisiones-con-lenguaje-de-programacion-processing/</link>
		<comments>http://mosaic.uoc.edu/2013/04/24/deteccion-de-colisiones-con-lenguaje-de-programacion-processing/#comments</comments>
		<pubDate>Wed, 24 Apr 2013 07:51:48 +0000</pubDate>
		<dc:creator>Mosaic</dc:creator>
				<category><![CDATA[Oscar García Pañella]]></category>
		<category><![CDATA[Recursos]]></category>
		<category><![CDATA[animación]]></category>
		<category><![CDATA[multimedia]]></category>
		<category><![CDATA[Processing]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://mosaic.uoc.edu/?p=13063</guid>
		<description><![CDATA[En este ejemplo vamos a detectar si un objeto que llevamos literalmente “pegado” a nuestro cursor del ratón (un círculo rojo), colisiona con un número aleatorio de otros objetos (varios círculos verdes) dispuestos a lo largo de nuestro canvas. Además informaremos al usuario/a mediante texto de si se está produciendo la colisión o no. ]]></description>
				<content:encoded><![CDATA[<p>En este ejemplo vamos a detectar si un objeto que llevamos literalmente “pegado” a nuestro cursor del ratón (un círculo rojo), colisiona con un número aleatorio de otros objetos (varios círculos verdes) dispuestos a lo largo de nuestro canvas. Además informaremos al usuario/a mediante texto de si se está produciendo la colisión o no. El ejemplo tiene fines didácticos &nbsp;y por lo tanto no vamos a centrarnos en la más absoluta eficiencia por lo que respecta al cálculo. Eso lo podríamos hacer si ya tenemos muy claro este ejemplo precisamente. Veamos la apariencia de nuestro detector de colisiones en la figura 1.</p>
<p align="center"><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/colisiones.png" rel="lightbox[13063]"><img class="aligncenter size-large wp-image-13064" alt="colisiones" src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/colisiones-450x236.png" width="450" height="236" /></a>&nbsp;</p>
<p align="center"><i>Figura 1. En nuestro detector de colisiones entre círculos observamos como el sistema detecta si no hay colisión (“Not Collided”, izquierda) o si la hay (“Collided”, derecha).</i></p>
<p>Se trata de crear un programa que:</p>
<ul>
<li>Sitúe un círculo rojo en el lugar del ratón. De hecho el cursor se esconderá.</li>
<li>Sitúe un número determinado de círculos verdes en posiciones aleatorias.</li>
<li>Compare, si movemos el ratón, las posiciones relativas entre el círculo rojo y el resto de círculos verdes. Éstos tendrán que estar almacenados en un array (variable que contiene muchas variables) para tener acceso a sus posiciones XY en todo momento.</li>
<li>Determine si se está produciendo alguna colisión.</li>
<li>En caso afirmativo, lo reporte. Y en caso negativo, también.</li>
<li>Nos permita resituar aleatoriamente todos los círculos verdes en nuevas posiciones aleatorias de cara a seguir “jugando” en una “pantalla nueva y diferente”.</li>
</ul>
<p>Vamos a ello pues y empecemos con la primera porción de código (código 1).</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// We will test a collision detector</li><li>// by creating several circles (green)</li><li>// that might collide, or not, with</li><li>// another circle (red) that we are carrying via our mouse</li><li>&nbsp;</li><li>// The arrays to store the 2D coordinates</li><li>// for the greenish static circles</li><li>int[] objects_x_coord;</li><li>int[] objects_y_coord;</li><li>// The amount of circles to randomly locate</li><li>int amount_objects = 10;</li><li>// The radius of our circles</li><li>int radius_circles = 10;</li><li>&nbsp;</li><li>// The setup function to initialize everything</li><li>void setup(){</li><li>&nbsp;&nbsp;// Our window</li><li>&nbsp;&nbsp;size(400,400);</li><li>&nbsp;&nbsp;// No strokes for our rendered circles</li><li>&nbsp;&nbsp;noStroke();</li><li>&nbsp;&nbsp;// We create 2 arrays of amount_objects positions</li><li>&nbsp;&nbsp;objects_x_coord = new int[amount_objects];</li><li>&nbsp;&nbsp;objects_y_coord = new int[amount_objects];</li><li>&nbsp;&nbsp;// We initialize the content inside each position</li><li>&nbsp;&nbsp;// of the arrays with a randomly generated number</li><li>&nbsp;&nbsp;// to locate a number equal to amount_objects of circles</li><li>&nbsp;&nbsp;// in random locations</li><li>&nbsp;&nbsp;for(int counter = 0; counter &lt; amount_objects; counter++){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;objects_x_coord[counter] = (int)random(width);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;objects_y_coord[counter] = (int)random(height);</li><li>&nbsp;&nbsp;}</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 1. Variables e inicialización de nuestro detector de colisiones.</i></p>
<p>Observemos como iniciamos creando diversas variables globales. Además de las variables que permiten definir la cantidad de círculos verdes que deseamos generar así como el radio que deberán tener a la hora de dibujarlos (amount_objects, radius_circles), que por defecto indican 10 objetos de radio 10 píxeles, también creamos una pareja de arrays (objects_x_coord, objects_y_coord) para almacenar las coordenadas X e Y de cada uno de nuestros círculos verdes situados por la escena. Las coordenadas del círculo rojo que “viaja” con el ratón no deberán almacenarse ya que ya las tenemos (son las coordenadas del ratón que en <a href="http://processing.org/">Processing</a> pueden obtenerse en todo momento accediendo a las variables de sistema mouseX y mouseY).</p>
<p>En nuestra función de inicialización setup(), creamos una ventana de 400 x 400 píxeles y eliminamos el color de borde para nuestros círculos (se trata de un criterio puramente estético que podéis variar a gusto lógicamente). A continuación, “reservamos memoria” para nuestros arrays. Observemos que al declararlos como variables globales no definimos de cuantas posiciones los queríamos. Eso mismo hacemos ahora al determinar que deberán tener un número de posiciones igual al número de círculos verdes que deseemos generar en pantalla (amount_objects). Por último utilizamos una estructura de control de tipo FOR para recorrer todas las posiciones de ambos arrays, tantas como marque amount_objects, y situar en ellas sendos números aleatorios para las coordenadas X e Y de cada círculo verde, gracias a la función random(). Tengamos en cuenta que como es lógico, las coordenadas aleatorias en X las generamos entre 0 y el ancho de ventana (width) y de igual forma, las coordenadas en Y las generamos entre 0 y el alto de ésta (height).</p>
<p>En la figura 2 observamos las diferentes configuraciones que pueden producirse dependiendo de los valores que demos a nuestras variables globales amount_objects y radius_circles.</p>
<p align="center"><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/figura2_diferentesConfiguracionesDeObjetosYRadios.jpg" rel="lightbox[13063]"><img class="aligncenter size-large wp-image-13065" alt="figura2_diferentesConfiguracionesDeObjetosYRadios" src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/figura2_diferentesConfiguracionesDeObjetosYRadios-450x157.jpg" width="450" height="157" /></a>&nbsp;</p>
<p align="center"><i>Figura 2. Controlamos el radio de nuestros círculos y cuantos deseamos pintar a voluntad.</i></p>
<p>En la clásica función draw() de <a href="http://processing.org/">Processing</a>, y para nuestro programa, no reside la mayor “inteligencia” de nuestro reto. La tenemos en el código 2.</p>
<p></code><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// The infinite loop</li><li>void draw(){</li><li>&nbsp;&nbsp;// A black background for our canvas</li><li>&nbsp;&nbsp;background(0);</li><li>&nbsp;&nbsp;// We are to render several (amount_objects) static greenish circles</li><li>&nbsp;&nbsp;fill(0,255,0);</li><li>&nbsp;&nbsp;// We loop to render all the static circles</li><li>&nbsp;&nbsp;// because we define the radius as the variable to use (radius_circles)</li><li>&nbsp;&nbsp;// their magnitude in terms of axes is equal to radius_circles*2</li><li>&nbsp;&nbsp;for(int counter = 0; counter &lt; amount_objects; counter++){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;ellipse(objects_x_coord[counter],objects_y_coord[counter],radius_circles*2,radius_circles*2);</li><li>&nbsp;&nbsp;}</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 2. Función draw() y sus funciones más bien básicas en este ejemplo.</i></p>
<p>Observemos que básicamente se trata de limpiar el fondo a cada iteración (color negro), definir el color verde como el que deseamos emplear para los círculos generados aleatoriamente y almacenados en nuestros dos arrays y, por último, utilizar una estructura de control en bucle de tipo FOR para recorrerlos (tenemos tantos como “diga” la variable amount_objects) y pintar, para cada uno, una elipse con longitud igual entre ejes (por tanto es un círculo) de valor radius_circles*2 en las posiciones XY de cada uno de nuestros objetos estáticos.</p>
<p>En el código 3 observamos cual es la función que realmente detecta y calcula las colisiones. Se trata del evento de ratón o callback mouseMoved, que será llamado cada vez que movamos el periférico en cualquier dirección. Es más eficiente hacerlo en este evento que dentro de la función draw() porque así sólo realizaremos los cálculos cuando realmente haya posibilidad de colisionar, es decir cada vez que movamos el ratón.</p>
<p></code><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// The callback to be called by the system if the mouse moves</li><li>void mouseMoved(){</li><li>&nbsp;&nbsp;// We need several variables to evaluate</li><li>&nbsp;&nbsp;// the distance between our dynamic reddish circle</li><li>&nbsp;&nbsp;// to the rest of static greenish circles</li><li>&nbsp;&nbsp;// plus to print some text to the window</li><li>&nbsp;&nbsp;boolean collided = false;</li><li>&nbsp;&nbsp;float[] distance_between_circles;</li><li>&nbsp;&nbsp;float magnitude_of_distance;</li><li>&nbsp;&nbsp;String s;</li><li>&nbsp;</li><li>&nbsp;&nbsp;// We initialize a float array the will</li><li>&nbsp;&nbsp;// be used when calculating the distance</li><li>&nbsp;&nbsp;// between circle's centers</li><li>&nbsp;&nbsp;distance_between_circles = new float[2];</li><li>&nbsp;&nbsp;// We evaluate the distance from our dynamic circle's center</li><li>&nbsp;&nbsp;// to the centers of all the static circles. If there's a single</li><li>&nbsp;&nbsp;// case where we detect a collision, we set the collided variable</li><li>&nbsp;&nbsp;// to true</li><li>&nbsp;&nbsp;// Colliding implies that the distance between 2 circles is less</li><li>&nbsp;&nbsp;// than the sum of their radius</li><li>&nbsp;&nbsp;for(int counter = 0; counter &lt; amount_objects; counter++){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;distance_between_circles[0] = objects_x_coord[counter] - mouseX;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;distance_between_circles[1] = objects_y_coord[counter] - mouseY;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;magnitude_of_distance = distance_between_circles[0]*distance_between_circles[0]+</li><li>&nbsp;&nbsp;&nbsp;&nbsp;distance_between_circles[1]*distance_between_circles[1];</li><li>&nbsp;&nbsp;&nbsp;&nbsp;magnitude_of_distance = sqrt(magnitude_of_distance);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;if (magnitude_of_distance&lt;radius_circles*2){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;collided = true;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;// We render our dynamic reddish circle</li><li>&nbsp;&nbsp;// as it moves with the mouse</li><li>&nbsp;&nbsp;fill(255,0,0);</li><li>&nbsp;&nbsp;ellipse(mouseX,mouseY,radius_circles*2,radius_circles*2);</li><li>&nbsp;&nbsp;// We render some text in white</li><li>&nbsp;&nbsp;fill(255);</li><li>&nbsp;&nbsp;// Different text depending on what happened</li><li>&nbsp;&nbsp;if (collided){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;s = &quot;Collided :(&quot;;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;text(s, 10, 370, 200, 40);</li><li>&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;else{</li><li>&nbsp;&nbsp;&nbsp;&nbsp;s = &quot;Not collided :)&quot;;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;text(s, 10, 370, 200, 40);</li><li>&nbsp;&nbsp;}</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 3. Callback de movimiento de ratón mouseMoved. Detecta y calcula las colisiones.</i></p>
<p>El fundamento de la detección de colisiones entre dos círculos puede observarse en la figura 3. Es sencillo y se basa en el más puro sentido común. Dos círculos empiezan a colisionar siempre y cuando las distancias entre sus centros sean inferiores a la suma de sus dos radios.</p>
<p align="center"><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/figura3_cuandoSeTocanDosCirculos.jpg" rel="lightbox[13063]"><img class="aligncenter size-full wp-image-13066" alt="figura3_cuandoSeTocanDosCirculos" src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/figura3_cuandoSeTocanDosCirculos.jpg" width="379" height="282" /></a>&nbsp;</p>
<p align="center"><i>Figura 3. Cómo saber si dos círculos colisionan.</i></p>
<p>En el callback de movimiento de ratón mouseMoved es donde se realizan estos cálculos. Para calcular una distancia entre dos puntos podemos remitirnos a la <a href="http://es.wikipedia.org/wiki/Distancia">Álgebra Euclidiana</a> de forma que: <i>la distancia entre dos puntos de coordenadas (x1,y1) y (x2,y2) se obtiene como la raíz cuadrada de (x2-x1)<sup>2</sup>+(y2-y1)<sup>2</sup></i>. Y ese es justamente el cálculo que realiza nuestro código 3 entre los pares de puntos que se obtienen de relacionar el centro de nuestro círculo rojo (coordenadas mouseX y mouseY) con los sucesivos centros de todos los círculos verdes (coordenadas objects_x_coord[counter] y objects_y_coord[counter]). Todo dentro de la estructura de control de tipo FOR que los recorre todos (variable counter que va de 0 a amount_objects).</p>
<p>En el caso que la distancia calculada (magnitude_of_distance) sea inferior a la suma de los dos radios (como en este caso todos son iguales hacemos radius_circles*2), dispondremos que se ha producido una colisión y por lo tanto activaremos nuestra variable de tipo Boolean (variable collided pasa a ser true).</p>
<p>Después del proceso de detección de colisión, procedemos a pintar nuestro círculo rojo como una elipse centrada en las coordenadas del ratón. También imprimimos un texto en pantalla en color blanco que, dependiendo del valor de la variable collided, será uno u otro.</p>
<p>Terminamos con el código 4, que fundamentalmente controla el evento de clic de ratón para que en caso de accionarlo, recalcule las posiciones de todos nuestros círculos verdes tal y como ya hicimos al inicializar en la función setup().</p>
<p></code><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// The callback to be called by the system if the user</li><li>// clicks the mouse</li><li>void mousePressed(){</li><li>&nbsp;&nbsp;// We will re-generate all static circle's positions</li><li>&nbsp;&nbsp;for(int counter = 0; counter &lt; amount_objects; counter++){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;objects_x_coord[counter] = (int)random(width);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;objects_y_coord[counter] = (int)random(height);</li><li>&nbsp;&nbsp;}</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 4. Callback de clic de ratón </i>mousePressed<i>. Si hacemos clic se recalculan las posiciones.</i></p>
<p>En el código 5 podemos observar el programa al completo.</p>
<p></code><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// We will test a collision detector</li><li>// by creating several circles (green)</li><li>// that might collide, or not, with</li><li>// another circle (red) that we are carrying via our mouse</li><li>&nbsp;</li><li>// The arrays to store the 2D coordinates</li><li>// for the greenish static circles</li><li>int[] objects_x_coord;</li><li>int[] objects_y_coord;</li><li>// The amount of circles to randomly locate</li><li>int amount_objects = 10;</li><li>// The radius of our circles</li><li>int radius_circles = 10;</li><li>&nbsp;</li><li>// The setup function to initialize everything</li><li>void setup(){</li><li>&nbsp;&nbsp;// Our window</li><li>&nbsp;&nbsp;size(400,400);</li><li>&nbsp;&nbsp;// No strokes for our rendered circles</li><li>&nbsp;&nbsp;noStroke();</li><li>&nbsp;&nbsp;// We create 2 arrays of amount_objects positions</li><li>&nbsp;&nbsp;objects_x_coord = new int[amount_objects];</li><li>&nbsp;&nbsp;objects_y_coord = new int[amount_objects];</li><li>&nbsp;&nbsp;// We initialize the content inside each position</li><li>&nbsp;&nbsp;// of the arrays with a randomly generated number</li><li>&nbsp;&nbsp;// to locate a number equal to amount_objects of circles</li><li>&nbsp;&nbsp;// in random locations</li><li>&nbsp;&nbsp;for(int counter = 0; counter &lt; amount_objects; counter++){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;objects_x_coord[counter] = (int)random(width);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;objects_y_coord[counter] = (int)random(height);</li><li>&nbsp;&nbsp;}</li><li>}</li><li>&nbsp;</li><li>// The infinite loop</li><li>void draw(){</li><li>&nbsp;&nbsp;// A black background for our canvas</li><li>&nbsp;&nbsp;background(0);</li><li>&nbsp;&nbsp;// We are to render several (amount_objects) static greenish circles</li><li>&nbsp;&nbsp;fill(0,255,0);</li><li>&nbsp;&nbsp;// We loop to render all the static circles</li><li>&nbsp;&nbsp;// because we define the radius as the variable to use (radius_circles)</li><li>&nbsp;&nbsp;// their magnitude in terms of axes is equal to radius_circles*2</li><li>&nbsp;&nbsp;for(int counter = 0; counter &lt; amount_objects; counter++){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;ellipse(objects_x_coord[counter],objects_y_coord[counter],radius_circles*2,radius_circles*2);</li><li>&nbsp;&nbsp;}</li><li>}</li><li>&nbsp;</li><li>// The callback to be called by the system if the mouse moves</li><li>void mouseMoved(){</li><li>&nbsp;&nbsp;// We need several variables to evaluate</li><li>&nbsp;&nbsp;// the distance between our dynamic reddish circle</li><li>&nbsp;&nbsp;// to the rest of static greenish circles</li><li>&nbsp;&nbsp;// plus to print some text to the window</li><li>&nbsp;&nbsp;boolean collided = false;</li><li>&nbsp;&nbsp;float[] distance_between_circles;</li><li>&nbsp;&nbsp;float magnitude_of_distance;</li><li>&nbsp;&nbsp;String s;</li><li>&nbsp;</li><li>&nbsp;&nbsp;// We initialize a float array the will</li><li>&nbsp;&nbsp;// be used when calculating the distance</li><li>&nbsp;&nbsp;// between circle's centers</li><li>&nbsp;&nbsp;distance_between_circles = new float[2];</li><li>&nbsp;&nbsp;// We evaluate the distance from our dynamic circle's center</li><li>&nbsp;&nbsp;// to the centers of all the static circles. If there's a single</li><li>&nbsp;&nbsp;// case where we detect a collision, we set the collided variable</li><li>&nbsp;&nbsp;// to true</li><li>&nbsp;&nbsp;// Colliding implies that the distance between 2 circles is less</li><li>&nbsp;&nbsp;// than the sum of their radius</li><li>&nbsp;&nbsp;for(int counter = 0; counter &lt; amount_objects; counter++){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;distance_between_circles[0] = objects_x_coord[counter] - mouseX;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;distance_between_circles[1] = objects_y_coord[counter] - mouseY;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;magnitude_of_distance = distance_between_circles[0]*distance_between_circles[0]+</li><li>&nbsp;&nbsp;&nbsp;&nbsp;distance_between_circles[1]*distance_between_circles[1];</li><li>&nbsp;&nbsp;&nbsp;&nbsp;magnitude_of_distance = sqrt(magnitude_of_distance);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;if (magnitude_of_distance&lt;radius_circles*2){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;collided = true;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;// We render our dynamic reddish circle</li><li>&nbsp;&nbsp;// as it moves with the mouse</li><li>&nbsp;&nbsp;fill(255,0,0);</li><li>&nbsp;&nbsp;ellipse(mouseX,mouseY,radius_circles*2,radius_circles*2);</li><li>&nbsp;&nbsp;// We render some text in white</li><li>&nbsp;&nbsp;fill(255);</li><li>&nbsp;&nbsp;// Different text depending on what happened</li><li>&nbsp;&nbsp;if (collided){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;s = &quot;Collided :(&quot;;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;text(s, 10, 370, 200, 40);</li><li>&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;else{</li><li>&nbsp;&nbsp;&nbsp;&nbsp;s = &quot;Not collided :)&quot;;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;text(s, 10, 370, 200, 40);</li><li>&nbsp;&nbsp;}</li><li>}</li><li>&nbsp;</li><li>// The callback to be called by the system if the user</li><li>// clicks the mouse</li><li>void mousePressed(){</li><li>&nbsp;&nbsp;// We will re-generate all static circle's positions</li><li>&nbsp;&nbsp;for(int counter = 0; counter &lt; amount_objects; counter++){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;objects_x_coord[counter] = (int)random(width);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;objects_y_coord[counter] = (int)random(height);</li><li>&nbsp;&nbsp;}</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 5. Programa de detección de colisiones con </i><a href="http://processing.org/"><i>Processing</i></a><i> al completo.</i></p>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://mosaic.uoc.edu/2013/04/24/deteccion-de-colisiones-con-lenguaje-de-programacion-processing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Realidad aumentada con lenguaje de programación Processing</title>
		<link>http://mosaic.uoc.edu/2013/04/24/realidad-aumentada-con-lenguaje-de-programacion-processing/</link>
		<comments>http://mosaic.uoc.edu/2013/04/24/realidad-aumentada-con-lenguaje-de-programacion-processing/#comments</comments>
		<pubDate>Wed, 24 Apr 2013 07:41:31 +0000</pubDate>
		<dc:creator>Mosaic</dc:creator>
				<category><![CDATA[Oscar García Pañella]]></category>
		<category><![CDATA[Recursos]]></category>
		<category><![CDATA[Processing]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[realidad aumentada]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://mosaic.uoc.edu/?p=13001</guid>
		<description><![CDATA[Gracias a la Realidad Aumentada podemos añadir elementos sintéticos, clásicamente en 3D, a los ya de por sí reales. Con una cámara y gracias a la ayuda de un patrón que ésta interpretará, posicionaremos un objeto en 3D superpuesto a la imagen de video de nuestra escena.]]></description>
				<content:encoded><![CDATA[<p>Gracias a la <a href="http://es.wikipedia.org/wiki/Realidad_aumentada">Realidad Aumentada</a> podemos añadir elementos sintéticos, clásicamente en 3D, a los ya de por sí reales. Con una cámara, una webcam en nuestro caso, y gracias a la ayuda de un patrón que ésta interpretará, posicionaremos un objeto en 3D superpuesto a la imagen de video de nuestra escena (lo que grave la cámara básicamente). Podéis observar diversos ejemplos de Realidad Aumentada (<a href="http://es.wikipedia.org/wiki/Realidad_aumentada">R.A.</a>) aquí.</p>
<p>Gracias a la figura 1, nos hacemos una idea de lo que ocurrirá en nuestro programa. Todo de la mano de la librería específica para <a href="http://processing.org/">Processing</a> <a href="http://nyatla.jp/nyartoolkit/wp/?page_id=729">NyARToolkit</a> así como de la librería <a href="http://code.google.com/p/saitoobjloader/">SaitoObjLoader </a>para carga de modelos 3D. Ésta última se compone fundamentalmente de un fichero <a href="http://en.wikipedia.org/wiki/Java_language">JAVA </a>(OBJLoader.jar) que contiene todas las funciones <a href="http://processing.org/">Processing</a> que accederemos desde nuestro código.</p>
<p><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/figura1_unaAppDeRAConProcessing.jpg" rel="lightbox[13001]"><img class="aligncenter size-large wp-image-13002" alt="Una esfera en 3D y con textura flota ante nuestros ojos gracias a la R.A." src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/figura1_unaAppDeRAConProcessing-450x355.jpg" width="450" height="355" /></a></p>
<p align="center"><i>Figura 1. Una esfera en 3D y con textura flota ante nuestros ojos gracias a la </i><a href="http://es.wikipedia.org/wiki/Realidad_aumentada"><i>R.A.</i></a><i></i></p>
<p>Antes de empezar es importante que dentro del directorio de nuestro sketch <a href="http://processing.org/">Processing</a>, creemos dos subdirectorios. Sugiero que lo hagáis de esta forma:</p>
<ul>
<li>Subdirectorio “data”. Almacena el modelo y la textura asociada (ficheros “sphere.jpg”, “sphere.mtl” y “sphere.obj”), los ficheros relativos a los marcadores de <a href="http://es.wikipedia.org/wiki/Realidad_aumentada">R.A.</a> que emplearemos (los clásicos que vienen de ejemplo con la librería, es decir los ficheros de patrón “patt.hiro” y “patt.kanji”) y el de configuración de cámara que también nos facilita la librería de <a href="http://es.wikipedia.org/wiki/Realidad_aumentada">R.A.</a> (“camera_para.dat”). Para el caso del modelo 3D, decir que este tipo de ficheros pueden generarse fácilmente desde cualquier programa de edición 2D (textura) y 3D (modelo). De hecho tanto el fichero <a href="http://en.wikipedia.org/wiki/Wavefront_.obj_file">.MTL</a> como el <a href="http://en.wikipedia.org/wiki/Wavefront_.obj_file">.OBJ</a> pueden editarse con un editor de texto.</li>
</ul>
<p><b><i>Nota</i></b><i>: podemos ver los patrones de </i><a href="http://es.wikipedia.org/wiki/Realidad_aumentada"><i>R.A.</i></a><i> que se adjuntan a la librería en la figura 2.</i></p>
<ul>
<li>Subdirectorio “code”. Almacena las librerías en sí. Todas ellas, es decir los ficheros&nbsp; “OBJLoader.jar”, “NyAR4psg.jar” y “NyARToolkit.jar” que habremos descargado.</li>
</ul>
<p align="center"><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/04/patrones-2.png" rel="lightbox[13001]"><img class="aligncenter size-large wp-image-13004" alt=". Patrones de R.A. de nuestra librería NyARToolkit" src="http://mosaic.uoc.edu/wp-content/uploads/2013/04/patrones-2-450x225.png" width="450" height="225" /></a>&nbsp;</p>
<p align="center"><i>Figura 2. Patrones de </i><a href="http://es.wikipedia.org/wiki/Realidad_aumentada"><i>R.A.</i></a><i> de nuestra librería </i><a href="http://nyatla.jp/nyartoolkit/wp/?page_id=729"><i>NyARToolkit</i></a><i>.</i></p>
<p>Vamos a comentar la inicialización de todo el sistema, disponible en el código 1.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// We are testing some Augmented Reality</li><li>// features by using the NyARToolkit libraries</li><li>// available at http://nyatla.jp/nyartoolkit/wp/</li><li>// and loading a 3D model with the SaitoObjLoader</li><li>// library available at http://code.google.com/p/saitoobjloader/</li><li>// Therefore we import them</li><li>import processing.video.*;</li><li>import jp.nyatla.nyar4psg.*;</li><li>import saito.objloader.*;</li><li>// We define several objects:</li><li>// A camera, a multimarker and a 3D model</li><li>Capture myCam;</li><li>MultiMarker myMarkers;</li><li>OBJModel model;</li><li>// The setup() initialization function to be called once</li><li>void setup() {</li><li>&nbsp;&nbsp;// Our window resolution</li><li>&nbsp;&nbsp;// We activate Processing 3D to be able to render the 3D model</li><li>&nbsp;&nbsp;size(640,480,P3D);</li><li>&nbsp;&nbsp;// We define our color mode</li><li>&nbsp;&nbsp;// by using RGB colors within the [0,100] interval</li><li>&nbsp;&nbsp;colorMode(RGB, 100);</li><li>&nbsp;&nbsp;// Augmented Reality initialization</li><li>&nbsp;&nbsp;// We will use some of the markers and files</li><li>&nbsp;&nbsp;// provided by the NyARToolkit library</li><li>&nbsp;&nbsp;// We begin by attaching our webcam captures to the window</li><li>&nbsp;&nbsp;myCam=new Capture(this,640,480);</li><li>&nbsp;&nbsp;// We initialize our multiMarker object myMarkers</li><li>&nbsp;&nbsp;// The file camera_para.dat is provided by the creator of the library:</li><li>&nbsp;&nbsp;// It needs to be placed inside the data folder within the sketch</li><li>&nbsp;&nbsp;myMarkers=new MultiMarker(this,width,height,&quot;camera_para.dat&quot;,NyAR4PsgConfig.CONFIG_PSG);</li><li>&nbsp;&nbsp;// We will load 2 markers within our multiMarker object (myMarkers)</li><li>&nbsp;&nbsp;// Both markers are provided by the creator of the library:</li><li>&nbsp;&nbsp;// patt.hiro and patt.kanji (inside the data folder within the sketch)</li><li>&nbsp;&nbsp;myMarkers.addARMarker(&quot;patt.hiro&quot;,80);</li><li>&nbsp;&nbsp;myMarkers.addARMarker(&quot;patt.kanji&quot;,80); </li><li>&nbsp;&nbsp;// We load our 3D model which is placed inside the data folder within the sketch</li><li>&nbsp;&nbsp;model = new OBJModel(this, &quot;sphere.obj&quot;, &quot;absolute&quot;, TRIANGLES);</li><li>&nbsp;&nbsp;model.enableDebug();</li><li>&nbsp;&nbsp;// We globally scale the 3D model by a factor of 20</li><li>&nbsp;&nbsp;// Plus to that, we center it and we enable texturing onto it</li><li>&nbsp;&nbsp;model.scale(20);</li><li>&nbsp;&nbsp;model.translateToCenter();</li><li>&nbsp;&nbsp;model.enableTexture();</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 1. Variables e inicialización de nuestro sistema de </i><a href="http://es.wikipedia.org/wiki/Realidad_aumentada"><i>R.A.</i></a><i></i></p>
<p>Lo primero que hacemos es importar las librerías que necesitamos, tanto en lo relativo al video y al sistema de <a href="http://es.wikipedia.org/wiki/Realidad_aumentada">R.A.</a> (import processing.video.* y import jp.nyatla.nyar4psg.*) como a la carga del modelo 3D (import saito.objloader.*). A continuación, y en nuestra función de inicialización (setup()) creamos una ventana de 640 x 480 píxeles y además activamos la funcionalidad 3D de <a href="http://processing.org/">Processing </a>(P3D). Definimos el modo de color con el que trabajaremos (valores de color <a href="http://es.wikipedia.org/wiki/Modelo_de_color_RGB">RGB</a> restringidos entre los valores de 0, mínimo, y 100, máximo) e inicializamos nuestros objetos myCam, myMarkers y model, llamando a sus constructores:</p>
<ul>
<li>myCam: nueva adquisición de vídeo vía webcam de 640 x 480 píxeles por cuadro.</li>
</ul>
<ul>
<li>myMarkers: un objeto que puede contener a más de un patrón de <a href="http://es.wikipedia.org/wiki/Realidad_aumentada">R.A.</a> (en nuestro caso dos), que se configura según valores estándares de la librería (observad como le pasamos al constructor el ancho y alto de nuestra ventana para que se ajuste). Gracias a su método addARMarker le asociaremos los dos patrones de <a href="http://es.wikipedia.org/wiki/Realidad_aumentada">R.A.</a> “patt.hiro” y “patt.kanji”.</li>
</ul>
<p><b><i>NOTA</i></b><i>: para imprimir los patrones se utilizan los ficheros en formato .PDF que se adjuntan a la librería de </i><a href="http://es.wikipedia.org/wiki/Realidad_aumentada"><i>R.A.</i></a><i> Es decir, “pattHiro.pdf” y “pattKanji.pdf”. No se utilizan los ficheros “patt.hiro” y “patt.kanji”.</i></p>
<ul>
<li>model: Observemos que estamos determinando que deseamos pintar en base a triángulos y que vamos a cargar el modelo “sphere.obj”, al cual nos referíamos antes. Vale la pena resaltar los métodos scale(20), translateToCenter() y enableTexture(). Gracias a ellos escalamos uniformemente el modelo 3D en sus 3 direcciones XYZ (lo hacemos 20 veces más grande), lo centramos a los ejes de coordenadas de mundo y después activamos las texturas para éste. El escalado nos permite darle el tamaño que deseemos.</li>
</ul>
<p>En el código 2 empezamos por comprobar que nuestro objeto de tipo cámara myCam se encuentre disponible gracias a un condicional de tipo if (es decir la webcam en funcionamiento normal) de forma que si no es así, cancelamos la ejecución del programa. A partir de ahí, leemos una imagen de ésta (myCam.read()) e iniciamos la detección de los patrones (marcadores) en la imagen (myMarkers.detect(myCam)). Recordemos que tenemos dos posibles en nuestro objeto MultiMarker myMarkers. Pintamos el fondo de negro, aplicamos como fondo la imagen que se obtiene desde la webcam (haciendo que el vídeo ocupe toda nuestra ventana) y definimos un bucle for que dará dos “vueltas”, una por cada marcador.</p>
<p>De nuevo se utiliza un condicional if para validar que efectivamente existe un patrón en la imagen dado que en caso contrario no es necesario hacer nada (si no hay marcador, no hay modelo 3D a cargar).&nbsp; A continuación se inician las transformaciones asociadas a la aparición de uno cualquiera de los dos patrones. Éstas operan entre los métodos myMarkers.beginTransform(i) y myMarkers.endTransform(), dónde la variable i hace referencia al marcador que se esté empleando. Observemos como las transformaciones, que afectarán al modelo 3D, consisten en una traslación en Z (sumamos 20 unidades a la profundidad) y de escalado (dividimos sus dimensiones entre 10). Finalmente procedemos a pintar el modelo 3D en sí, gracias al método draw() del objeto model.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// The infinite loop</li><li>void draw()</li><li>{</li><li>&nbsp;&nbsp;// Our 3D model will be a textured sphere</li><li>&nbsp;</li><li>&nbsp;&nbsp;// First thing we need to evaluate that the webcam is working properly</li><li>&nbsp;&nbsp;if (myCam.available() !=true) {</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;</li><li>&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;// If our webcam works as it should, we read an image from it</li><li>&nbsp;&nbsp;myCam.read();</li><li>&nbsp;&nbsp;// We start the detection of markers</li><li>&nbsp;&nbsp;myMarkers.detect(myCam);</li><li>&nbsp;&nbsp;// Black background for our window</li><li>&nbsp;&nbsp;background(0);</li><li>&nbsp;&nbsp;// We apply the background</li><li>&nbsp;&nbsp;myMarkers.drawBackground(myCam);</li><li>&nbsp;&nbsp;// We analyze if any of our 2 markers is present</li><li>&nbsp;&nbsp;for(int i=0;i&amp;lt;2;i++){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;if((!myMarkers.isExistMarker(i))){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// If any of the 2 markers was present</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// we will render our 3D model (textured sphere)</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// We will apply two 3D transformations</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// to scale and translate our 3D model properly</li><li>&nbsp;&nbsp;&nbsp;&nbsp;myMarkers.beginTransform(i);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;translate(0,0,20);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scale(0.1);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// We render our 3D model!</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;model.draw();</li><li>&nbsp;&nbsp;&nbsp;&nbsp;myMarkers.endTransform();</li><li>&nbsp;&nbsp;}</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 2. Bucle de iteración draw().</i></p>
<p>Disponéis del programa completo en el código 3. Disfrutadlo y variadlo a voluntad! Saludos.</p>
<p><!--DEVFMTCODE--><pre class="devcodeblock" title="processing"><div class="devcodeoverflow"><ol><li>// We are testing some Augmented Reality</li><li>// features by using the NyARToolkit libraries</li><li>// available at http://nyatla.jp/nyartoolkit/wp/</li><li>// and loading a 3D model with the SaitoObjLoader</li><li>// library available at http://code.google.com/p/saitoobjloader/</li><li>// Therefore we import them</li><li>import processing.video.*;</li><li>import jp.nyatla.nyar4psg.*;</li><li>import saito.objloader.*;</li><li>// We define several objects:</li><li>// A camera, a multimarker and a 3D model</li><li>Capture myCam;</li><li>MultiMarker myMarkers;</li><li>OBJModel model;</li><li>// The setup() initialization function to be called once</li><li>void setup() {</li><li>&nbsp;&nbsp;// Our window resolution</li><li>&nbsp;&nbsp;// We activate Processing 3D to be able to render the 3D model</li><li>&nbsp;&nbsp;size(640,480,P3D);</li><li>&nbsp;&nbsp;// We define our color mode</li><li>&nbsp;&nbsp;// by using RGB colors within the [0,100] interval</li><li>&nbsp;&nbsp;colorMode(RGB, 100);</li><li>&nbsp;&nbsp;// Augmented Reality initialization</li><li>&nbsp;&nbsp;// We will use some of the markers and files</li><li>&nbsp;&nbsp;// provided by the NyARToolkit library</li><li>&nbsp;&nbsp;// We begin by attaching our webcam captures to the window</li><li>&nbsp;&nbsp;myCam=new Capture(this,640,480);</li><li>&nbsp;&nbsp;// We initialize our multiMarker object myMarkers</li><li>&nbsp;&nbsp;// The file camera_para.dat is provided by the creator of the library:</li><li>&nbsp;&nbsp;// It needs to be placed inside the data folder within the sketch</li><li>&nbsp;&nbsp;myMarkers=new MultiMarker(this,width,height,&quot;camera_para.dat&quot;,NyAR4PsgConfig.CONFIG_PSG);</li><li>&nbsp;&nbsp;// We will load 2 markers within our multiMarker object (myMarkers)</li><li>&nbsp;&nbsp;// Both markers are provided by the creator of the library:</li><li>&nbsp;&nbsp;// patt.hiro and patt.kanji (inside the data folder within the sketch)</li><li>&nbsp;&nbsp;myMarkers.addARMarker(&quot;patt.hiro&quot;,80);</li><li>&nbsp;&nbsp;myMarkers.addARMarker(&quot;patt.kanji&quot;,80);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;// We load our 3D model which is placed inside the data folder within the sketch</li><li>&nbsp;&nbsp;model = new OBJModel(this, &quot;sphere.obj&quot;, &quot;absolute&quot;, TRIANGLES);</li><li>&nbsp;&nbsp;model.enableDebug();</li><li>&nbsp;&nbsp;// We globally scale the 3D model by a factor of 20</li><li>&nbsp;&nbsp;// Plus to that, we center it and we enable texturing onto it</li><li>&nbsp;&nbsp;model.scale(20);</li><li>&nbsp;&nbsp;model.translateToCenter();</li><li>&nbsp;&nbsp;model.enableTexture();</li><li>}</li><li>// The infinite loop</li><li>void draw()</li><li>{</li><li>&nbsp;&nbsp;// Our 3D model will be a textured sphere</li><li>&nbsp;&nbsp;// First thing we need to evaluate that the webcam is working properly</li><li>&nbsp;&nbsp;if (myCam.available() !=true) {</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;</li><li>&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;// If our webcam works as it should, we read an image from it</li><li>&nbsp;&nbsp;myCam.read();</li><li>&nbsp;&nbsp;// We start the detection of markers</li><li>&nbsp;&nbsp;myMarkers.detect(myCam);</li><li>&nbsp;&nbsp;// Black background for our window</li><li>&nbsp;&nbsp;background(0);</li><li>&nbsp;&nbsp;// We apply the background</li><li>&nbsp;&nbsp;myMarkers.drawBackground(myCam);</li><li>&nbsp;&nbsp;// We analyze if any of our 2 markers is present</li><li>&nbsp;&nbsp;for(int i=0;i&amp;lt;2;i++){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;if((!myMarkers.isExistMarker(i))){</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// If any of the 2 markers was present</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// we will render our 3D model (textured sphere)</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// We will apply two 3D transformations</li><li>&nbsp;&nbsp;&nbsp;&nbsp;// to scale and translate our 3D model properly</li><li>&nbsp;&nbsp;&nbsp;&nbsp;myMarkers.beginTransform(i);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;translate(0,0,20);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scale(0.1);</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// We render our 3D model!</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;model.draw();</li><li>&nbsp;&nbsp;&nbsp;&nbsp;myMarkers.endTransform();</li><li>&nbsp;&nbsp;}</li><li>}</li></ol></div></pre><!--END_DEVFMTCODE--></p>
<p align="center"><i>Código 3. Programa completo de </i><a href="http://es.wikipedia.org/wiki/Realidad_aumentada"><i>R.A.</i></a><i></i></p>
]]></content:encoded>
			<wfw:commentRss>http://mosaic.uoc.edu/2013/04/24/realidad-aumentada-con-lenguaje-de-programacion-processing/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Processing práctico (Parte 2 de 3)</title>
		<link>http://mosaic.uoc.edu/2013/03/26/processing-practico-parte-2-de-3/</link>
		<comments>http://mosaic.uoc.edu/2013/03/26/processing-practico-parte-2-de-3/#comments</comments>
		<pubDate>Tue, 26 Mar 2013 10:26:12 +0000</pubDate>
		<dc:creator>Mosaic</dc:creator>
				<category><![CDATA[Número 106]]></category>
		<category><![CDATA[Oscar García Pañella]]></category>
		<category><![CDATA[Recursos]]></category>
		<category><![CDATA[animación]]></category>
		<category><![CDATA[interacción]]></category>
		<category><![CDATA[multimedia]]></category>
		<category><![CDATA[Processing]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://mosaic.uoc.edu/?p=12645</guid>
		<description><![CDATA[Segunda entrega de tutoriales sobre Processing que nos presenta Oscar García Pañella, Doctor en Realidad Virtual. Processing es un lenguaje de programación de código abierto ideal para gente que quiere crear imágenes, animaciones e interacciones que ha ido evolucionado desde una forma básica hasta convertirse en una herramienta de producción profesional.]]></description>
				<content:encoded><![CDATA[<p><a href="http://processing.org/">Processing</a>&nbsp;se trata de un lenguaje de programación de código abierto ideal para gente que quiere crear imágenes, animaciones e interacciones. Este software ha ido evolucionando a lo largo del tiempo hasta convertirse en una herramienta de producción profesional. Esta es la segunda entrega de los tutoriales elaborados por Oscar García Pañella para empezar a trabajar con Processing desde diversas perspectivas:</p>
<p><a href="http://mosaic.uoc.edu/2013/03/25/carga-de-un-modelo-3d-con-lenguaje-de-programacion-processing/"><strong>Carga de un Modelo 3D con Lenguaje de Programación Processing</strong></a></p>
<p><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/03/3D1.jpg" rel="lightbox[12645]"><img class="size-medium wp-image-12536 alignleft" alt="3D1" src="http://mosaic.uoc.edu/wp-content/uploads/2013/03/3D1-87x75.jpg" width="87" height="75" /></a>En este ejemplo vamos a cargar un modelo 3D en formato OBJ con textura JPG gracias a Processing. Le dotaremos de un par de funcionalidades. Por una parte, rotará alrededor de su eje de simetría. Además, podremos hacer clic con el ratón alternando la funcionalidad de vista de los triángulos que conforman el modelo.</p>
<p><a href="http://mosaic.uoc.edu/2013/03/25/imagenes-y-luts-en-programacion-processing/"><strong>Imágenes y LUTs en Programación Processing</strong></a></p>
<p><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/03/LUT1.jpg" rel="lightbox[12645]"><img class="alignleft size-medium wp-image-12560" alt="LUT1" src="http://mosaic.uoc.edu/wp-content/uploads/2013/03/LUT1-92x75.jpg" width="92" height="75" /></a>Una LUT o “Look Up Table” es un procedimiento por el cual podemos variar las características de una imagen al retocar sus píxeles, uno a uno. Se trata de recorrerlos todos, obtener su valor y, precisamente en base a la&nbsp;<a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a>&nbsp;que diseñemos, retocarlo de manera que pase a ser diferente. Las&nbsp;<a href="http://en.wikipedia.org/wiki/Lookup_table">LUT</a>s se utilizan en todos los programas de edición y retoque fotográfico e incluso en algunas cámaras digitales para aplicar filtros a nuestras imágenes: pasarla de color a blanco y negro, pasarla a tono sepia, variar su brillo, etc.</p>
<p><a href="http://mosaic.uoc.edu/2013/03/25/efecto-dinamico-de-pointillism-en-imagenes-via-programacion-processing/"><strong>Efecto dinámico de “Puntillismo” en Imágenes vía Programación Processing</strong></a></p>
<p><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/03/LUTT2.jpg" rel="lightbox[12645]"><img class="alignleft size-medium wp-image-12605" alt="LUTT2" src="http://mosaic.uoc.edu/wp-content/uploads/2013/03/LUTT2-93x75.jpg" width="93" height="75" /></a>Vamos a realizar un sencillo programa Processing que cargará una imagen de disco duro y le aplicará un efecto de “Puntillismo” siempre y cuando pulsemos una vez uno de los botones del ratón (siempre dentro de la imagen). Un efecto de filtro como si, por ejemplo, estuviéramos mirando desde el otro lado de un curioso cristal tallado.</p>
<p><a href="http://mosaic.uoc.edu/2013/03/25/sonido-con-lenguaje-de-programacion-processing-primer-ejemplo/"><strong>Sonido con Lenguaje de Programación Processing. Primer ejemplo.</strong></a></p>
<p><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/03/so1-e1363193120481.jpg" rel="lightbox[12645]"><img class="alignleft size-medium wp-image-12630" alt="so1" src="http://mosaic.uoc.edu/wp-content/uploads/2013/03/so1-e1363193120481-76x75.jpg" width="76" height="75" /></a>Utilizamos la librería Minim para cargar y reproducir un fichero de extensión y formato .MP3 en nuestro equipo. Además vamos a visualizar “la canción” por lo que respecta a las amplitudes de sus canales izquierdo y derecho. La librería Minim se instala por defecto con Processing aunque es recomendable actualizarla.</p>
<p><a href="http://mosaic.uoc.edu/2013/03/25/sonido-con-lenguaje-de-programacion-processing-segundo-ejemplo/"><strong>Sonido con Lenguaje de Programación Processing. Segundo ejemplo.</strong></a></p>
<p><a href="http://mosaic.uoc.edu/wp-content/uploads/2013/03/so2-e1363194429869.jpg" rel="lightbox[12645]"><img class="alignleft size-medium wp-image-12640" alt="so2" src="http://mosaic.uoc.edu/wp-content/uploads/2013/03/so2-e1363194429869-100x75.jpg" width="100" height="75" /></a>En este ejemplo vamos a utilizar la librería Minim para cargar y reproducir un fichero de extensión y formato .MP3 en nuestro equipo. Además vamos a cargar una imagen de fondo y a visualizar “la canción” con dos “altavoces” que generaremos vía código, por lo que respecta a las amplitudes de sus canales.</p>
]]></content:encoded>
			<wfw:commentRss>http://mosaic.uoc.edu/2013/03/26/processing-practico-parte-2-de-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WebCat: Esqueuomorfismo, la ruptura de la metáfora</title>
		<link>http://mosaic.uoc.edu/2013/03/26/webcat-esqueuomorfismo-la-ruptura-de-la-metafora/</link>
		<comments>http://mosaic.uoc.edu/2013/03/26/webcat-esqueuomorfismo-la-ruptura-de-la-metafora/#comments</comments>
		<pubDate>Tue, 26 Mar 2013 10:25:39 +0000</pubDate>
		<dc:creator>Mosaic</dc:creator>
				<category><![CDATA[Número 106]]></category>
		<category><![CDATA[Recursos]]></category>
		<category><![CDATA[Webcat]]></category>
		<category><![CDATA[#webcat]]></category>
		<category><![CDATA[dispositivos móviles]]></category>
		<category><![CDATA[esqueuomorfismo]]></category>
		<category><![CDATA[experiencia de usuario]]></category>
		<category><![CDATA[móvil]]></category>

		<guid isPermaLink="false">http://mosaic.uoc.edu/?p=12768</guid>
		<description><![CDATA[El WebCat es un punto de encuentro entre profesionales del sector web donde se abordan asuntos diversos con el objetivo de trabajar y transmitir una idea concreta al público. El pasado 13 de febrero tuvo lugar un nuevo encuentro del que presentamos la charla de Máximo Gavete sobre el concepto 'esqueuomorfismo' aplicado a los dispositivos móviles.]]></description>
				<content:encoded><![CDATA[<p><strong>El WebCat es el punto de encuentro entre profesionales del sector web (desarrolladores, diseñadores, emprendedores, etc.) abierto a cualquier persona interesada en esta parcela.</strong></p>
<p>Dentro de WebCat se abordan asuntos diversos, tanto de forma introductoria como especializada, mediante breves exposiciones de no más de quince minutos con el objetivo de trabajar y transmitir una idea concreta al público.</p>
<p>El pasado 13 de febrero tuvo lugar un nuevo encuentro del que a continuación presentamos una breve e interesante muestra. Es la charla de Máximo Gavete sobre el concepto &#8216;esqueuomorfismo&#8217; aplicado a los dispositivos móviles.</p>
<h4>Máximo Gavete &#8211; Esqueuomorfismo: La ruptura de la metáfora</h4>
<p><iframe src="http://player.vimeo.com/video/62684973" height="281" width="500" allowfullscreen="" frameborder="0"></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://mosaic.uoc.edu/2013/03/26/webcat-esqueuomorfismo-la-ruptura-de-la-metafora/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
