Universitat Oberta de Catalunya

Realidad aumentada con lenguaje de programación Processing

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, 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 (R.A.) aquí.

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 Processing NyARToolkit así como de la librería SaitoObjLoader para carga de modelos 3D. Ésta última se compone fundamentalmente de un fichero JAVA (OBJLoader.jar) que contiene todas las funciones Processing que accederemos desde nuestro código.

Una esfera en 3D y con textura flota ante nuestros ojos gracias a la R.A.

Figura 1. Una esfera en 3D y con textura flota ante nuestros ojos gracias a la R.A.

Antes de empezar es importante que dentro del directorio de nuestro sketch Processing, creemos dos subdirectorios. Sugiero que lo hagáis de esta forma:

  • Subdirectorio “data”. Almacena el modelo y la textura asociada (ficheros “sphere.jpg”, “sphere.mtl” y “sphere.obj”), los ficheros relativos a los marcadores de R.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 R.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 .MTL como el .OBJ pueden editarse con un editor de texto.

Nota: podemos ver los patrones de R.A. que se adjuntan a la librería en la figura 2.

  • Subdirectorio “code”. Almacena las librerías en sí. Todas ellas, es decir los ficheros  “OBJLoader.jar”, “NyAR4psg.jar” y “NyARToolkit.jar” que habremos descargado.
. Patrones de R.A. de nuestra librería NyARToolkit

Figura 2. Patrones de R.A. de nuestra librería NyARToolkit.

Vamos a comentar la inicialización de todo el sistema, disponible en el código 1.

// We are testing some Augmented Reality
// features by using the NyARToolkit libraries
// available at http://nyatla.jp/nyartoolkit/wp/
// and loading a 3D model with the SaitoObjLoader
// library available at http://code.google.com/p/saitoobjloader/
// Therefore we import them
import processing.video.*;
import jp.nyatla.nyar4psg.*;
import saito.objloader.*;
// We define several objects:
// A camera, a multimarker and a 3D model
Capture myCam;
MultiMarker myMarkers;
OBJModel model;
// The setup() initialization function to be called once
void setup() {
// Our window resolution
// We activate Processing 3D to be able to render the 3D model
size(640,480,P3D);
// We define our color mode
// by using RGB colors within the [0,100] interval
colorMode(RGB, 100);
// Augmented Reality initialization
// We will use some of the markers and files
// provided by the NyARToolkit library
// We begin by attaching our webcam captures to the window
myCam=new Capture(this,640,480);
// We initialize our multiMarker object myMarkers
// The file camera_para.dat is provided by the creator of the library:
// It needs to be placed inside the data folder within the sketch
myMarkers=new MultiMarker(this,width,height,"camera_para.dat",NyAR4PsgConfig.CONFIG_PSG);
// We will load 2 markers within our multiMarker object (myMarkers)
// Both markers are provided by the creator of the library:
// patt.hiro and patt.kanji (inside the data folder within the sketch)
myMarkers.addARMarker("patt.hiro",80);
myMarkers.addARMarker("patt.kanji",80);
// We load our 3D model which is placed inside the data folder within the sketch
model = new OBJModel(this, "sphere.obj", "absolute", TRIANGLES);
model.enableDebug();
// We globally scale the 3D model by a factor of 20
// Plus to that, we center it and we enable texturing onto it
model.scale(20);
model.translateToCenter();
model.enableTexture();
}

Código 1. Variables e inicialización de nuestro sistema de R.A.

Lo primero que hacemos es importar las librerías que necesitamos, tanto en lo relativo al video y al sistema de R.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 Processing (P3D). Definimos el modo de color con el que trabajaremos (valores de color RGB restringidos entre los valores de 0, mínimo, y 100, máximo) e inicializamos nuestros objetos myCam, myMarkers y model, llamando a sus constructores:

  • myCam: nueva adquisición de vídeo vía webcam de 640 x 480 píxeles por cuadro.
  • myMarkers: un objeto que puede contener a más de un patrón de R.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 R.A. “patt.hiro” y “patt.kanji”.

NOTA: para imprimir los patrones se utilizan los ficheros en formato .PDF que se adjuntan a la librería de R.A. Es decir, “pattHiro.pdf” y “pattKanji.pdf”. No se utilizan los ficheros “patt.hiro” y “patt.kanji”.

  • 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.

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.

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).  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.

// The infinite loop
void draw()
{
// Our 3D model will be a textured sphere

// First thing we need to evaluate that the webcam is working properly
if (myCam.available() !=true) {
return;
}
// If our webcam works as it should, we read an image from it
myCam.read();
// We start the detection of markers
myMarkers.detect(myCam);
// Black background for our window
background(0);
// We apply the background
myMarkers.drawBackground(myCam);
// We analyze if any of our 2 markers is present
for(int i=0;i<2;i++){
if((!myMarkers.isExistMarker(i))){
continue;
}
// If any of the 2 markers was present
// we will render our 3D model (textured sphere)
// We will apply two 3D transformations
// to scale and translate our 3D model properly
myMarkers.beginTransform(i);
translate(0,0,20);
scale(0.1);
// We render our 3D model!
model.draw();
myMarkers.endTransform();
}
}

Código 2. Bucle de iteración draw().

Disponéis del programa completo en el código 3. Disfrutadlo y variadlo a voluntad! Saludos.

// We are testing some Augmented Reality
// features by using the NyARToolkit libraries
// available at http://nyatla.jp/nyartoolkit/wp/
// and loading a 3D model with the SaitoObjLoader
// library available at http://code.google.com/p/saitoobjloader/
// Therefore we import them
import processing.video.*;
import jp.nyatla.nyar4psg.*;
import saito.objloader.*;
// We define several objects:
// A camera, a multimarker and a 3D model
Capture myCam;
MultiMarker myMarkers;
OBJModel model;
// The setup() initialization function to be called once
void setup() {
// Our window resolution
// We activate Processing 3D to be able to render the 3D model
size(640,480,P3D);
// We define our color mode
// by using RGB colors within the [0,100] interval
colorMode(RGB, 100);
// Augmented Reality initialization
// We will use some of the markers and files
// provided by the NyARToolkit library
// We begin by attaching our webcam captures to the window
myCam=new Capture(this,640,480);
// We initialize our multiMarker object myMarkers
// The file camera_para.dat is provided by the creator of the library:
// It needs to be placed inside the data folder within the sketch
myMarkers=new MultiMarker(this,width,height,"camera_para.dat",NyAR4PsgConfig.CONFIG_PSG);
// We will load 2 markers within our multiMarker object (myMarkers)
// Both markers are provided by the creator of the library:
// patt.hiro and patt.kanji (inside the data folder within the sketch)
myMarkers.addARMarker("patt.hiro",80);
myMarkers.addARMarker("patt.kanji",80);
// We load our 3D model which is placed inside the data folder within the sketch
model = new OBJModel(this, "sphere.obj", "absolute", TRIANGLES);
model.enableDebug();
// We globally scale the 3D model by a factor of 20
// Plus to that, we center it and we enable texturing onto it
model.scale(20);
model.translateToCenter();
model.enableTexture();
}
// The infinite loop
void draw()
{
// Our 3D model will be a textured sphere
// First thing we need to evaluate that the webcam is working properly
if (myCam.available() !=true) {
return;
}
// If our webcam works as it should, we read an image from it
myCam.read();
// We start the detection of markers
myMarkers.detect(myCam);
// Black background for our window
background(0);
// We apply the background
myMarkers.drawBackground(myCam);
// We analyze if any of our 2 markers is present
for(int i=0;i<2;i++){
if((!myMarkers.isExistMarker(i))){
continue;
}
// If any of the 2 markers was present
// we will render our 3D model (textured sphere)
// We will apply two 3D transformations
// to scale and translate our 3D model properly
myMarkers.beginTransform(i);
translate(0,0,20);
scale(0.1);
// We render our 3D model!
model.draw();
myMarkers.endTransform();
}
}

Código 3. Programa completo de R.A.

6 comentarios

Deja un comentario

  1. Hola.He pro bado el código de realidad aumentada, pero me da un error: “The constructor MultiMarker (MultiMarker, int, int, String, NyAR4PsgConfig) is undefined”.
    ¿Cómo puedo solucionarlo?
    Lo siento por mi español… :))
    Hasta pronto.

    Stefania

    Responder
  2. Saludos desde el Peru.
    He leido tu articulo … podrias asistirme al respecto, tengo varias dudas con que programar para RA y sea lo mas compatible con todos lo sistema. hay tantos aplicaciones metaio, Ar constructores clasicos pero al final estoy confundido. Tu podrias darme algun alcance, la gracias anticipadas por tu respuesta.

    Responder
  3. Hola, me agrado el tema, tengo una pregunta, si quisieramos cargar un video o una iman en vez de un modelo 3d como le podemos hacer??, gracias

    Responder
  4. Hola,tengo un problemilla con la llamada al metodo myMarkers.drawBackground(myCam). Al llamar a este metodo causa la excepción “java.lang.RuntimeException: java.lang.NoClassDefFoundError: processing/core/PGraphics3D” y no encuentro la solución por ningun lado. He probado con otros ejemplos que trae nyar4psg pero siempre me da ese error. He intentado cambiar drawBackground(myCam) por la función image(myCam,0,0) que pinta la pantalla con la imagen que toma la cámara y funciona, pero no me reconoce ningún marcador y ya no se si es por no haber llamado a drawBackground o que.

    Uso processing 2.0.1 y NyARToolKit 1.3.1 bajo Windows 8.

    Responder
    • La versión 2 de Processing parece que provoca ese error. A mi paso lo mismo. Usa la versión 1.5 de Processing, con ella no he tenido problemas para trabajar con RA usando la librería NyARToolKit

      Saludos.

  5. Quisiera saber si conocen una librería para processing que permita tener marcadores de R.A. de cualquier foto.

    Responder

Deja un comentario