33

0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

  • Upload
    vonhu

  • View
    229

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes
Page 2: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

1

0. Índice.

Contenido

Página

0. Índice.

1

1. Introducción. 1.1 Problema a resolver.

1.1.1 Alcance del problema. 1.2 Resultados esperados

2 3

4

2. Antecedentes.

5

3. Objetivos. 3.1. Objetivo General. 3.2. Objetivos específicos.

6

4. Metodología. 4. 1. Desarrollar las imágenes (realidad aumentada). 4.2. Adaptación de la matriz de estimulación.

7

8

6. Desarrollo. 6.1. Infraestructura requerida. 6.2. Implementación de captura de video. 6.3. Implementación de realidad aumentada.

6.3.1. Funcionamiento de NyARToolKit. 6.3.2. Instalación de NyArToolKit. 6.3.3. Adaptación e integración de NyArToolKit.

6.4. Diseño de Modelos (iconos) y matriz de estimulación. 6.4.1. Matriz de estimulación.

9

10

12 13

15

7. Resultados. 7.1. Pantalla de Realidad Aumentada. 7.2. Pantalla Matriz de estimulación. 7.3. Ejecución de matriz de estimulación y “Nyar_netbeans”.

16

17

8. Conclusiones.

18

9. Referencias.

19

Anexo 1, Clase MultiNyAR.java 20

Anexo 2, Clase MarkerModel.java 22

Anexo 3, Clase DetectMarkers.java 24

Anexo 4, Clase PropManager.java 26

Anexo 5, Modelos 30

Anexo 6, Marcadores 31

Anexo 7, Matriz 31

Page 3: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

2

1. Introducción.

Dentro del campo de la ingeniería de rehabilitación, es común descubrir que existen pacientes que se encuentran disminuidos en sus capacidades motrices, ya sea con pérdida parcial o total de la movilidad, por lesión en la médula espinal como secuela de algún accidente o enfermedades como la esclerosis lateral amiotrófica (ELA), o enfermedades crónicas degenerativas que ataquen las neuronas o nervios encargados de controlar los músculos de manera voluntaria. Por esta razón se están desarrollando técnicas para ayudar a mejorar su calidad de vida, con el objetivo de establecer una vía de comunicación entre un dispositivo computacional o electrónico-mecánico y un paciente con las características mencionadas [1]. Este desarrollo se ha usado desde los estudios de Farwell y Donchin[2], los cuales han planteado algunas soluciones mediante el desarrollo de interfaces cerebro-computadora (BCI) para lograr en un paciente o usuario, una forma de interactuar con el entorno, sin la utilización de las vías musculares.

De acuerdo con la teoría de sistemas, la BCI tiene una entrada, (Ej. La actividad electroencefalográfica del paciente), los comandos del dispositivo como salida, y los componentes internos que traducen la entrada en la salida; así como un protocolo que indica el inicio y el tiempo de operaciones[1]. De manera general para este caso la BCI (P300_Speller) básicamente se compone de lo siguiente:

Adquisición de la señal: De manera no invasiva, mediante electrodos y sistema de registro de EEG.

Procesamiento: Clasificación de señales, comparación con el estímulo. Estimulación: Software de estimulación, matriz de comandos.

Como parte del aprovechamiento que resulta del uso de una BCI, el desarrollo de un sistema de brazo robótico, debe lograr que el paciente pueda interactuar con su entorno de manera activa. Este sistema está basado en una BCI que es clasificada como exógena [2], es decir, está basada en el paradigma de Potenciales Provocados. Este tipo de fenómenos tienen dependencia con un estímulo o evento y pueden constituir respuestas primarias o complejas dependiendo del tipo de evento, que en este caso se le conoce como evento raro (odd-ball). El paradigma de evento raro se caracteriza por la ocurrencia de un complejo de ondas que están relacionadas con los procesos de actualización de la memoria de trabajo (estímulo visual, reconocimiento del evento, reconocimiento del objetivo y actualización de memoria [3]). Este complejo lo conforman las ondas: P100, N100, P200, N200, P300, N400.

Page 4: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

3

1.1. Problema a resolver.

El sistema BCI2000 se está utilizando actualmente en el Laboratorio la cual otorga soluciones para adaptarse en diversas tareas de estímulo - evocación del potencial.

La propuesta de este proyecto consiste en desarrollar una interfaz gráfica de usuario (GUI) que tenga la capacidad de adaptarse a algunos datos del P300_Speller y los asocie con movimientos o grados de libertad que un brazo robótico logra realizar [4]. El brazo robótico (BR) fue diseñado imitando los movimientos elementales de las articulaciones de un brazo humano. Esencialmente, y para este proyecto, el BR cuenta con cuatro partes flexibles: mano (abrir y cerrar pinzas), flexión o extensión de muñeca, flexión o extensión de codo, así como el movimiento del hombro en dos sentidos. También el BR cuenta con una interfaz digital y un software para su control por medio del cual se le envían los comandos para manipular las partes flexibles del BR mencionadas. De manera que el usuario (paciente) pueda manejar el BR mediante comandos de identificación visual, es decir, que el paciente consiga reconocer fácilmente en la pantalla algunos movimientos (representados por iconos integrados gráficamente en la imagen del BR) que deban ser realizados por el BR, al fijar su atención en un icono de movimiento específico y buscarlo en la matriz de estimulación de la BCI. Para lograr lo anterior se debe hacer una adaptación del sistema de deletreo existente en el LINI, y así lograr la estimulación por medio de iconos o figuras que el paciente reconozca como ordenes al robot que desea manipular.

1.1.1. Alcance del problema.

Gran parte de las personas con lesiones en el tronco cerebral, a menudo puede usar movimientos oculares para generar respuestas y otorgar comandos simples, o inclusive utilizar un procesador de textos (Ej. Aplicación P300_Speller basada en el deletreador de Donchin y Farwell[2]). Por lo que el desarrollo de este proyecto se determina en un sistema que controle el BR de manera remota y que a su vez, resulte amable para el paciente, utilizando los recursos que el sistema BCI2000 otorga, se busca adaptar los comandos necesarios para la movilidad del BR, usando imágenes representativas (identificadores) de cada comando, se agregan estos identificadores a la imagen de video capturada en vivo y se procesa el video por medio de realidad aumentada. De esta forma se busca que el diseño resulte útil para una rápida y sencilla identificación de los comandos que el BR requiere para su utilización. Se pretende con esta implementación que el paciente tenga una relación más intuitiva y amable entre el control del brazo y la acción deseada.

Page 5: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

4

1.2. Resultados esperados.

Se busca una forma de integrar las funciones del BR mediante un ambiente de realidad aumentada y que pueda ser manipulado de manera sencilla por el usuario o paciente que ve en una pantalla de computadora las acciones que el BR realiza. Dicho de otra forma, la adquisición y procesamiento de la imagen se realiza en una computadora con una cámara de video ubicada frente al robot, así como la interfaz digital (tarjeta digital) que comanda al mismo, entonces el usuario visualiza la pantalla dividida en: una sección con la imagen en realidad aumentada con los identificadores de control sobre el robot, y en otra sección esos mismos identificadores o iconos de control en una matriz con la estimulación agregada por el sistema de BCI. De esta forma el sistema BCI queda ejecutándose en otra computadora (Figura 1).

Este proyecto se trata de desarrollar teniendo siempre en cuenta que en todo caso, el paciente al estar mermado de sus capacidades motrices, obtenga una mejora en su calidad de vida al participar de manera activa en su entorno, de manera que pueda comandar el BR de manera fácil e intuitiva como se observa en la Figura 1.

Figura 1. Esquema representativo del sistema.

Page 6: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

5

2. Antecedentes.

La Realidad Aumentada se ha desarrollado como una herramienta contemporánea que se basa en la adquisición de gráficos en tiempo real por medio de una cámara de video, y por medio de un procesamiento digital, se colocan elementos ficticios en la pantalla los cuales están conectados con el mundo real mediante la identificación de patrones reconocibles por un sistema de procesamiento de video. De manera virtual estos elementos pueden interactuar con el ambiente al fijarse sobre el escenario como si existieran en el entorno, sin importar si este se mueve o el observador se mueve, el objeto queda sometido a la realidad.

Actualmente se han utilizado diversas aplicaciones de la realidad aumentada (RA) y realidad virtual, para establecer un vínculo más intuitivo, natural y amigable entre el paciente y el sistema BCI. Es el caso del trabajo presentado en [5], el cual utiliza un sistema BCI adaptado en realidad virtual y RA, para introducir al usuario por medio de una representación gráfica humana del paciente en un entorno provisto de funciones y controles visuales que a su vez resultan en la estimulación y la fijación de la mirada en objetos inexistentes en la realidad para controlar los comandos del sistema virtual.

De modo que estas técnicas de RA están siendo empleadas en la rehabilitación de pacientes, como es el caso de un dispositivo dado a conocer en [6]. El cual es una silla de ruedas que es controlada por medio de un visor, este dispositivo se conecta a una cámara de video y de esta forma en la pantalla del paciente se observa el entorno y los obstáculos en él, así mismo el paciente percibe comandos básicos para el control de la silla de ruedas que su vez resultan en la estimulación – respuesta que el sistema BCI traduce en comandos básicos para el control del dispositivo.

Page 7: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

6

3. Objetivos.

3.1. Objetivo General.

Desarrollar una aplicación que utilice un ambiente gráfico para mejorar el sistema de control de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes en video del brazo, los comandos, representados por iconos de los posibles “movimientos” del robot. Dichos iconos deben ser observados por el paciente sobre cada articulación del robot en una pantalla de computadora, y en otra sección de la pantalla se mostrarán los mismos iconos, pero relacionados con el sistema de estimulación o matriz de estimulación del sistema BCI.

3.2. Objetivos específicos.

Fusionar las imágenes en video de la “realidad” con identificadores sobre las partes móviles del robot que indiquen al usuario que icono visualizar en la matriz para controlarlo, de manera que aunque el brazo se mueva o el observador se mueva, los iconos sigan fijos en las partes correspondientes del brazo robótico.

Relacionar los iconos sobre la imagen del BR con los elementos de la matriz de estimulación para interpretar el resultado de la BCI como una orden para el BR.

Page 8: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

7

4. Metodología.

Para abordar el proyecto y obtener los resultados esperados se ha dividido la metodología en dos etapas:

4. 1. Desarrollar las imágenes (realidad aumentada).

Se deben fusionar las imágenes en video de la “realidad” con identificadores sobre las partes móviles del robot con el fin de que indiquen al usuario, que icono visualizar en la matriz para controlarlo, de manera que aunque el brazo se mueva ó el observador se mueva, los iconos sigan fijos en el robot.

a) En esta fase del proyecto se seleccionan e investigan las herramientas para la programación, compilación y ejecución de aplicaciones conociendo las versiones de las bibliotecas de ARToolKit en los lenguajes posibles, C++ o Java.

b) Una vez que después de la investigación se seleccionó una Interfaz de Desarrollo Integrado adecuado (IDE por sus siglas en ingles Integrated Development Environment) se deben adaptar e instalar en la computadora las bibliotecas para que estén disponibles para el IDE.

c) A continuación se considera la captura de imágenes de video de una Web Cam. Por lo que en esta parte se desarrolla una aplicación sencilla para aprender a adaptar la información proporcionada por la cámara y reconocer un dispositivo de video.

d) Al seleccionar una variante adecuada de ARToolKit, se deben instalar las clases para adaptarlas posteriormente y compilar los programas. En primer lugar crear una aplicación sencilla de RA que logre poner un objeto virtual en la pantalla. Y Posteriormente esta misma debe acondicionarse para soportar 5 objetos distintos en pantalla, los cuales representan los 5 grados de libertad de los movimientos básicos del robot.

Page 9: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

8

4.2. Adaptación de la matriz de estimulación.

En esta parte de la metodología, se busca el diseño de identificadores útiles para comandar el BR de manera intuitiva e identificable para el usuario. Se pretende lograr dibujos icónicos que hagan alusión a una orden específica, los cuales deben relacionarse con el sistema de estimulación (matriz de estimulación) de P300_Speller, cada icono de la aplicación se integrará a la matriz de estimulación como si se tratase de los caracteres que el mismo deletreador utiliza habitualmente para estimular al usuario mediante la fijación de la mirada en un carácter en específico:

a) En primer lugar, es necesario diseñar y adaptar identificadores adecuados para esta aplicación y que a su vez puedan presentarse en la matriz de estimulación. Esta parte se efectúa por medio de una aplicación desarrolladora de objetos gráficos en tercera dimensión (3D) como Blender, que pueda generar objetos en 3D en un formato soportados por la aplicación de RA, pero que a su vez puedan también ser plasmados mediante dibujos en dos dimensiones para la matriz de estimulación.

b) Se debe diseñar una matriz de estimulación adecuada para las funciones del BR, integrando los iconos gráficos con la aplicación de P300_Speller.

c) Una vez teniendo los iconos adecuados ya integrados a la matriz de estimulación, se

realizar pruebas para comprobar que el diseño de los elementos de la matriz cumplen con los requerimientos gráficos necesarios para lograr una estimulación teórica adecuada para el usuario.

Page 10: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

9

6. Desarrollo

6.1. Infraestructura requerida.

Hardware:

Cámara de video de puerto USB (Web Cam u otra). Computadora con sistema operativo Windows XP profesional. Brazo robótico (ya desarrollado).

Software:

Ambiente de desarrollo integrado (IDE) en Java Net Beans. Bibliotecas de NyARToolKit, Java 3d, JMF y JDK. Software de estimulación-evocación del sistema P300_Speller.

6.2. Implementación de captura de video. Al tomarse en cuenta la programación en Java y el IDE Net Beans 6.9, se busca implementar una aplicación sencilla que capture una imagen de video por medio de la Web Cam conectada como dispositivo USB, con el fin de familiarizarse con la captura de video y el reconocimiento de dispositivos que permitan estas funciones. Para este fin es necesario tener una plataforma de desarrollo de Java para soportar contenidos gráficos de desarrollo la cual se trata de JMF[8] (Java Media Framework) que es un conjunto de bibliotecas con funciones especiales que permite la reproducción de archivos multimedia (video, música), pero también permite capturar desde dispositivos externos (una webcam por ejemplo) video y audio. En primer lugar debe instalarse la aplicación de JMF en el sistema operativo Windows XP profesional Versión 5. Con los requerimientos mínimos de la versión de JMF que se describen en [8]. Posteriormente al indagar sobre aplicaciones basadas en JMF para captura de video, se toma en cuenta un tutorial en la red [9] que asiste el desarrollo de este tipo de aplicaciones:

1. Se crea un nuevo proyecto en Netbeans "CapturaFoto", donde se crean clases “Dispositivos.java”, “JMenuFormato”, y una clase "jmfPrincipal.java" del tipo jFrame la cual contendrá la GUI (Graphical User Interface). También se adjunta el archivo “properties.jmf” contenido en la carpeta de instalación de JMF el cual es necesario para reconocer los dispositivos. Se organizan las clases como se observa en la Figura 2.

Figura 2. Organización de clases y bibliotecas del tutorial “CapturaFoto”.

2. Posteriormente se adjuntan las librerías de JMF como se observa en la Figura 1. 3. Lo siguiente es tomar los códigos de libre distribución que se proporcionan en la fuente

[9] y se adaptan a las clases que tenemos en la Figura 2. 4. Se diseña una GUI con las características indicadas en el tutorial detallado en [9] y

posteriormente se realizan pruebas para corregir los posibles errores en esta adaptación.

Page 11: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

10

6.3. Implementación de realidad aumentada.

Al abordar el problema planteado, se necesita entender el funcionamiento de RA. Es así que después de consultar en fuentes y foros de internet resulta pertinente utilizar la biblioteca de ARToolKit en una versión para Java la cual sirve para la creación de aplicaciones que usan realidad aumentada. Para ello NyARToolKit [7] proporciona una serie de funciones para la captura de vídeo para la búsqueda de ciertos patrones en las imágenes capturadas, mediante técnicas de visión por computadora. También proporciona una serie de ejemplos, tutoriales y utilidades de gran ayuda al programador que quiera realizar este tipo de aplicaciones.

6.3.1. Funcionamiento de NyARToolKit.

En general para las aplicaciones de RA, existe la necesidad de calcular el punto de vista de la cámara, para así realizar las operaciones necesarias sobre los objetos virtuales, para que estos se integren correctamente en el mundo real. Es decir, al mostrar objetos virtuales de modo que el usuario realmente pueda asimilar que existen en el mundo real, se deben realizar transformaciones sobre esos objetos de modo que el usuario los vea (a través de la cámara o dispositivo de captura utilizado) en la posición, tamaño, orientación e iluminación, que esos objetos serían percibidos por el usuario en el mundo real en caso de que realmente estuvieran allí.

Para que una aplicación de RA pueda reconocer la realidad, deben utilizarse patrones con distintos elementos. Estos patrones de reconocimiento, en este caso estarían compuestos de una “plantilla” donde existe el dibujo de un cuadrado negro y en su interior un cuadrado blanco cuatro veces más pequeño en su centro, así como un dibujo sencillo en el interior del cuadrado blanco. El programa que se desarrollará, utilizará las funciones y utilidades proporcionadas por NyARToolKit y será capaz de detectar una de estas plantillas en las imágenes de vídeo capturadas. En la Figura 3, se muestra un ejemplo de estas plantillas.

Figura 3. Ejemplo de una plantilla de identificación.

Una vez que el sistema detecta una plantilla en una imagen, estudiando la orientación, posición y tamaño de la plantilla, la aplicación es capaz de calcular la posición y orientación relativa de la cámara respecto a la plantilla, y usando esta información podría pasar a dibujar el objeto correspondiente sobre la imagen capturada mediante bibliotecas externas a ARToolKit de modo que el objeto aparece sobre la plantilla en la posición, orientación y tamaño correspondiente al punto de vista de la cámara, si así se desea, pues existen otras posibilidades en las operaciones de estos procesos. El funcionamiento básico de una aplicación de ARToolkit es el siguiente:

1. Primero se realiza la adquisición de imágenes en video de la realidad mediante una cámara.

2. A continuación la imagen se umbraliza con cierto valor (threshold), de forma que los pixeles cuya intensidad supere el valor del umbral sean transformados en pixeles de color negro. El resto se transforman en píxeles blancos.

3. Se buscan y encuentran todos los marcos negros como el de la plantilla existente en la imagen de la Figura 2 (al umbralizar la imagen el marco aparece blanco y el cuadrado blanco aparece negro).

4. Se compara el interior del marco con las plantillas de las que se tiene información almacenada.

Page 12: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

11

5. Si la forma de la plantilla analizada y la plantilla almacenada coincide, se utiliza la información de tamaño y orientación de la plantilla almacenada para compararla con la plantilla que se ha detectado y así poder calcular la posición y orientación relativas de la cámara a la plantilla, y se guarda en una matriz.

6. Se utiliza esta matriz para establecer la posición y orientación de la cámara virtual (transformación de la vista), lo que equivale a una transformación de las coordenadas del objeto a dibujar.

7. Al colocar la cámara virtual en la misma posición y orientación que la cámara real, el objeto virtual se dibuja sobre la plantilla, se interpreta la escena en tres dimensiones como una imagen bidimensional (se renderiza) y se muestra la imagen resultante, que contiene la imagen del mundo real y el objeto virtual superpuesto, alineado sobre la plantilla.

Al realizar el desarrollo de este software, se busca el apoyo de distintas funciones predefinidas que la biblioteca NyARToolKit provee, las cuales logran resolver muchos de los pasos en el proceso mencionado.

Page 13: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

12

6.3.2. Instalación de NyArToolKit.

Para instalar las bibliotecas de NyArToolKit, se busca una versión compatible con NetBeans que contenga las clases básicas para el funcionamiento adecuado.

1.- Primero se crea un nuevo proyecto en NetBeans: Archivo -> Proyecto Nuevo -> Java -> Java Application que en este caso se nombra “Nyar_netbeans”. Dentro de este proyecto se crea una carpeta llamada “lib” en donde se agregan archivos que se encuentran en la biblioteca con referencia en [7]. Los archivos son los siguientes:

NyArtToolKit.jar portafolio.jar

2.- En esta parte se aprovecha la instalación de “Java Media Framework” revisada previamente en la sección 6.1. Por lo tanto se consideran los siguientes archivos que también deben importarse a la carpeta “lib”.

custom.jar customizer.jar jmf.jar jmf.properties jmf.properties.orig mediaplayer.jar multiplayer.jar sound.jar soundbank.gm

3.- En es necesario utilizar también la biblioteca de Java3D para Windows (j3d-1_5_2-windows-i586.zip) la cual se encuentra en la referencia [10]. Al revisar la biblioteca, una vez instalada la aplicación proporcionada, se buscan en la ubicación Java/ Java3D1.5.1libext los siguientes archivos los cuales deben copiarse en “lib”.

j3dcore.jar j3dutils.jar vecmath.jar

4.- Posteriormente se revisa el contenido de clases de la biblioteca NyArToolKit para tomar los archivos de Java, los cuales contienen los métodos esenciales para el desarrollo de la aplicación y se integran a la carpeta del proyecto Nyar_netbeans: Source Packages/<default package> por medio de una importación al paquete predeterminado:

DetectMarkers.java MarkerModel.java NyARMarkersBehavior.java PropManager.java SmoothMatrix.java MultiNyAR.java

5.- Luego se crea un nuevo package dentro de Source Packages que se nombra “Data”, que es donde se almacena el archivo camera_para.dat provisto por la paquetería descargada de NyArToolKit y que se encuentra en la carpeta Data. Este archivo se importa al package Data que creamos en el proyecto.

Este mismo package va a servir posteriormente para guardar todos los marcadores ya codificados en patrones legibles por la maquina (Anexo 6).

6.- Se crea también un nuevo package el cual se nombra “Model” cuya función es almacenar los modelos legibles por la aplicación en los formatos correspondientes, ya sean “.3ds” o “.obj”. Estos modelos son los “iconos” que el usuario podrá ver en la pantalla al momento de que la aplicación reconozca un patrón legible y claramente identificable.

Page 14: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

13

6.3.3. Adaptación e integración de NyArToolKit.

En esta parte es donde se llevan a cabo las adaptaciones del proyecto generado “Nyar_netbeans”, así como la integración de los modelos o iconos al relacionarlos con los marcadores codificados en lenguaje maquina:

1.- Al abrir en NetBeans la clase MultiNyAR.java se modifica la línea 26 observada en el Anexo 1 para otorgar la ruta de acceso para el archivo camera_para.dat el cual guardara todos los parámetros que se le ordenan al dispositivo, como la resolución, que en este caso se le fijan por medio de las variables enteras PWIDTH y PHEIGHT que se observan en la línea 27 y 28 del Anexo 1, con 640 y 480 respectivamente lo que significa un valor de 640x480 pixeles permisibles una vez averiguando los tamaños disponibles para la cámara.

2.- Dentro de la clase MultiNyAR.java (Anexo 1), las líneas 101 a la 126, declaran la representación de los modelos en tres dimensiones los cuales se relacionan con los patrones o marcadores codificados. Ejemplo:

Código 1.

1 MarkerModel mm1 = new MarkerModel("patt.hiro", "modelo4.3ds", 0.15, false); 2 if (mm1.getMarkerInfo() != null) { // creation was successful 3 sceneBG.addChild( mm1.getMoveTg() ); 4 detectMarkers.addMarker(mm1); 5 }

Se observa en el Código 1 en la línea 1, que el objeto mm1 del tipo MarkerModel (Anexo 2 línea 60) espera como parámetros: "patt.hiro"(marcador codificado), "modelo4.3ds"(modelo en 3d del icono con el que se relaciona el marcador), “0.15” (escala del modelo), “false” (si hay o no disponibles coordenadas de aparición).

En la línea 2 se observa que el método getMarkerInfo() verifica que existe información de la posición del marcador físico y si no la hay, entonces no puede presentarse el modelo y por lo tanto no puede arrojarse información de las coordenadas. Una vez validada la sentencia de la línea 2 del mismo código, las sentencias de la línea 3 y 4 simplemente permiten el seguimiento del modelo en relación con el marcador correspondiente. El proceso mencionado se repite para los 4 modelos restantes.

3.- Lo siguiente es modificar la línea 20 que se observa en el Anexo 2, se debe escribir la ruta donde se encuentran los marcadores ya decodificados pues allí es donde la clase MarkerModel adquiere los patrones codificados y aceptados por el sistema. Por ejemplo el marcador mostrado en la Figura 4, es codificado por medio de un generador de uso libre encontrado en la red [11], el cual convierte las imágenes permitidas como marcador en patrones (archivo de tipo .patt) ya sean a 8, 16, 43 y 64 bits, los cuales son legibles para la aplicación.

Figura 4. Marcador usado por la aplicación para ser detectado en el ambiente gráfico.

Para que un marcador pueda ser adecuado como patrón, debe tener un contorno en color negro de alrededor del 50% de la imagen total, y debe tener en su interior figuras asimétricas que sean difícil de perderse en un entorno umbralizado (mencionado en el apartado 2, 3, 4 y 5 del tema 6.2.1), también en el momento de ser presentado en la cámara, no debe tener obstrucciones ni interrupción alguna. Por esta razón deben realizarse múltiples codificaciones para un mismo marcador, seleccionado cuidadosamente los distintos niveles de bits, para probar con distintos escenarios físicos y corridas de la aplicación posibles hasta lograr que la codificación del patrón sea la óptima. La clase DetectMarkers.java (anexo 3) es la encargada de realizar la detección de los marcadores.

Page 15: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

14

4.- Cuando la detección del patrón en el entorno físico es exitoso, la clase PropManager.Java (Anexo 4) otorga el acondicionamiento de los modelos en 3d, para representarlos gráficamente y realizar el seguimiento, rotación, alejamiento o acercamiento de los modelos y que estos este relacionados con los cambios observados en el entorno físico. En estos términos el usuario proporciona el nombre de un archivo de objeto 3D para ser cargado por medio de la modificación de las líneas 94 anexo 4, en donde se establece la ruta donde se encuentran los modelos. La clase acepta una gran variedad de diferentes formatos de objetos en 3D. Y así una vez cargada, la imagen se puede mover y girar a lo largo de los ejes X, Y y Z así como realizar escalamientos prefijados. La posición y la información de rotación, y su ampliación se puede almacenar en un archivo 'coords' (que debe tener el mismo nombre que el archivo del modelo 3D" Coords.txt ") y para otorgar la ruta de estos archivos se debe modificar la línea 170 del anexo 4. La información de rotación se almacena como una serie de números de rotación en el archivo ‘coords’ con la siguiente regla:

1 = ROT_INCR positiva alrededor del eje x 2 = ROT_INCR negativa alrededor del eje x 3 = ROT_INCR positivo alrededor del eje y 4 = ROT_INCR negativa alrededor del eje y 5 = ROT_INCR positiva alrededor del eje z 6 = ROT_INCR negativa alrededor del eje z

6.4. Diseño de Modelos (iconos) y matriz de estimulación.

Con el propósito de diseñar modelos aptos para presentarse en pantalla como indicadores de movimientos en el BR, se utiliza la herramienta Blender 2.6 para diseñar los objetos tridimensionales (Figura 5). Por cuestiones de practicidad, se utilizaron los formatos .3ds para todos los diseños.

Figura 5. Diseño de modelos en 3D por medio de Blender.

Los modelos finales se pueden observar en el Anexo 5, los cuales son asignados por medio de marcadores (mostrados en Anexo 6). Cada modelo representa órdenes que se relacionan con los posibles movimientos que se le enviarán al BR, los cuales pueden sintetizarse en los siguientes:

Abrir o cerrar pinzas (gradual o completo), se relaciona con el modelo Icosfera (Figura 8, anexo 5).

Muñeca (flexión o extensión completa y gradual), se relaciona con el modelo Cubo (Figura 10, anexo 5).

Codo (flexión o extensión completa y gradual), se relaciona con el modelo Cilindro (Figura 9, anexo 5).

Rotación hombro en 2 sentidos (Gradual o completo), la apertura del hombro se relacionan con el Cono (Figura 6, anexo 5) y la rotación del hombro se relaciona con el Toroide (Figura 7, anexo 5).

Page 16: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

15

6.4.1 Matriz de estimulación.

Para el diseño de la matriz se realiza una configuración en el sistema P300_Speller, con una matriz de 5x6, la cual contiene imágenes que hacen alusión a los movimientos del robot, diferenciándose mediante los identificadores o figuras mencionadas en 6.4. A continuación en la Figura 13, se observa un ejemplo de cada elemento de la matriz que representa un movimiento del BR en específico.

Figura 13. Ejemplo genérico de movimientos posibles del BR.

Las figuras externas de la imagen mostrada en Figura 14, representan movimientos completos o flexiones completas a la izquierda o derecha respectivamente, ya sea el abrir o cerrar completamente. La imagen del centro (Figura 14), representa “home”, es decir regresar a la posición original. Así las imágenes izquierda y derecha de “home” representan movimientos graduales que tiene como posibilidad el BR en una flexión. Como puede observarse en la Figura 11 del Anexo 7 cada movimiento está relacionado con un modelo mencionado en 6.3.

a)

b)

c) d)

e)

Figura 14. Movimientos auxiliares de la matriz de estimulación.

La fila inferior de la matriz (Anexo7), cuenta con movimientos que sirven para auxiliar las órdenes, como se observa en la Figura 14-a),b), son órdenes de deshacer el último movimiento realizado, ya sea izquierda o derecha respectivamente. La Figura 14-b), representa la desconexión súbita que el usuario quiera generar. La Figura 14-c), representa el que todos los movimientos en curso regresen a su estado original y la Figura 14-d) representa un “alto” total de cualquier movimiento. Como ya se ha mencionado, el BR fue diseñado con la finalidad de imitar a un brazo humano, por lo que las flexiones y extensiones del brazo robótico están relacionados con movimientos habituales de un brazo humano.

Page 17: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

16

7. Resultados.

Al realizar las pruebas pertinentes en cada fase de la metodología se realizaron correcciones hasta que cada parte queda ajustada a los resultados esperados, los cuales pueden dividirse en dos grupos esenciales:

7.1. Pantalla de Realidad Aumentada.

Al momento de ejecutar el proyecto en Net Beans “Nyar_netbeans”, se genera automáticamente una aplicación autoejecutable, la cual puede encontrarse en la ruta del proyecto: Nyar_netbeans/dist/lib/Nyar_netbeans.jar, la cual es una aplicación que para ser instalada en cualquier computadora debe tener los requerimientos mencionados en 6.1 para la infraestructura de software y hardware.

Ahora se ejecuta el programa “Nyar_netbeans”, y aparece automáticamente la pantalla que

toma el flujo de imágenes provenientes de la Web Cam conectada vía USB al ordenador. Y la aplicación comienza a buscar los patrones en el entorno grafico como se muestra a continuación:

a)

b)

Figura 15. Captura de pantalla, detección de marcadores en el ambiente gráfico. La Figura 15-a), b) son capturas de pantalla en el momento en el que los patrones o

marcadores se presentan ante la cámara en posiciones arbitrarias y son reconocidos por el sistema como lecturas de posición y distancia para colocar los modelos correspondientes. Es importante mencionar que los marcadores deben estar libres de interrupciones, con buena iluminación y un espacio de separación considerable a partir del marco. Además existe un límite de inclinación razonable para una correcta exposición de los marcadores la cual no se ha calculado aún pero que es bastante flexible.

Page 18: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

17

Tomando en cuenta lo anterior, se procede a colocar los marcadores en las partes móviles del BR para realizar pruebas sobre el mismo. Y como resultado se obtiene lo que se observa en la Figura 16-a), b).

7.2. Pantalla Matriz de estimulación.

Una vez adaptada la matriz de estimulación al sistema P300_Speller, se procede a configurar los tiempos de estimulación y descansos factibles así como la ejecución del programa. Por lo que se obtienen estimulaciones mediante cambios de color que en este caso son cambios a negativos de las imágenes proyectadas en la matriz que se observa en el Anexo 7 a las frecuencias establecidas en la configuración por de facto en P300_Speller. Las pruebas hechas corroboran que la matriz es capaz de generar los cambios gráficos adecuados para una posible estimulación visual.

7.3. Ejecución de matriz de estimulación y “Nyar_netbeans”.

Se ejecuta la aplicación P300_Speller simultáneamente con la aplicación de realidad aumentada “Nyar_netbeans”, donde las ventanas queden a la par para una visualización en relación mutua. En la Figura 17 se observa este resultado.

Figura 17. Fotografía de la ejecución simultanea de los programas y el BR.

b) a)

Figura 16. Captura de pantalla. a) Detección de marcadores en el ambiente grafico sobre el BR. b) Marcadores fijos sobre el BR.

Page 19: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

18

8. Conclusiones.

Para llegar a los objetivos planteados en un principio, se tomaron decisiones en el uso de herramientas de software gracias a la literatura y la investigación referenciada en este proyecto, por lo que se alcanzaron los objetivos planteados. De manera que se generó un sistema de control del BR más amigable para el usuario, necesitando menor entrenamiento en la manipulación del control del BR. Las herramientas de Realidad aumentada pueden ser utilizadas en diversos campos de aplicación para la Ingeniería Biomédica. Este proyecto puede servir de ayuda en los desarrollos posteriores para conectar sistemas BCI con entornos gráficos más útiles y en diversos dispositivos de la ingeniería de rehabilitación.

Posteriormente este sistema podría generar una estimulación de potenciales provocados de la corteza visual directo de la pantalla de Realidad Aumentada y posiblemente mediante dispositivos de Realidad Virtual, lo que podría facilitar mucho la presentación del control de dispositivos robóticos o deletreadores basados en lecturas de EEG.

Así mismo se tiene aún la posibilidad de refinar este proyecto en conjunto con el desarrollo del BR para mejorar los tiempos de reacción, así como mejorar la RA para generar mejor calidad desde los gráficos hasta la velocidad de reacción.

También queda pendiente el envío de información del sistema P300_Speller a BCI2000 y a la tarjeta de interfaz del BR. Para mejorar la sincronización del sistema en conjunto y establecer mejores tiempos de ejecución que podrían llevarse a cabo expandiendo los requerimientos mínimos del sistema de video y procesamiento en los ordenadores. Así como seleccionado cámaras de calidades superiores para generar la adaptación más óptima y de mejor calidad.

Page 20: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

19

9. Referencias.

[1] Jonathan R. Wolpaw, Niels Birbaumer, Dennis J. McFarland, Gert Pfurtscheller, Theresa M. Vaughan. “Invited review: Brain–computer interfaces for communication and control. Clinical Neurophysiology“. No.

113 (2002) 767–791. 2 Marzo 2002.

[2] Farwell L.A y Donchin E. “Talking off top of your head: Toward a mental prosthesis utilizing event-related brain potentials”. Electroencephalography and clinical Neurophysiology, Elsevier Scientific Publishers Ireland. No. 70, Pag. 510-523, Ltd. 1988.

[3] Teodoro Solis-Escalante. T. de Ma. “Diseño e implementación de una Interfaz Cerebro-Computadora basada en Potenciales Evocados Visuales de Estado Estacionario”. Universidad Autónoma Metropolitana. Pag. 9-18. Julio de 2007.

[4] Felix Hernandez Reyez. T. de Lic. “Utilización de BCI como control de brazo robótico”. Universidad Autónoma Metropolitana. Diciembre 2011.

[5] J. Faller, R. Leeb, G. Pfurtscheller y R. Scherer. “Avatar navigation in virtual and augmented reality environments using an SSVEP BCI”. ICABB-2010, Venecia, Italia Octubre, Pag 14-16, 2010.

[6] Iñaki Iturrate, Javier M. Antelis, Andrea Kubler, y Javier Minguez. “A Noninvasnsive Brain-Actuated Wheelchair Based on a P300 Neurophysiological Protocol and Automated Navigation”. IEEE

TRANSACTIONS ON ROBOTICS, VOL. 25, NO. 3, Junio 2009.

[7] NyARToolkit Project. The NyARToolkit project website. Recuperado en marzo 2013,

http://nyatla.jp/nyartoolkit/wp/.

[8] Oracle. Oracle Technology Network Java SE. Recuperado en marzo 2013,

http://www.oracle.com/technetwork/java/javase/download-142937.html.

[9] ARCmop Java Programacion Solaris Linux. Java-linux-programación. JMF, Usando la webcam desde JAVA y guardando una Imagen. Recuperado en marzo 2013, publicado por Cmop en enero 14, 2010, http://cmop17.wordpress.com/2010/01/14/jmf-usando-la-webcam-desde-java-y-guardando-una-imagen/.

[10] Java 3DTM Downloads: Release Builds. The Source for Java Technology Collaboration. Recuperado en

marzo 2013. https://java3d.java.net/binary-builds.html.

[11] Marker”s” Generator Online Released!. Recuperado en Junio 2013. http://flash.tarotaro.org/blog/2009/07/12/mgo2/.

Page 21: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

20

Anexo 1.

Clase MultiNyAR.java

6 // MultiNyAR.java 7 // Andrew Davison, [email protected], April 2010 8 /* An Java3D NyARToolkit example using multiple markers and

models, 9 that reports position and rotation information. 10 NYARToolkit is available at: 11 http://nyatla.jp/nyartoolkit/wiki/index.php?NyARToolkit%20f

or%20Java.en 12 JMF also required: 13 http://java.sun.com/javase/technologies/desktop/media/jmf/ 14 NCSA Portfolio is used to load the models. It is available at: 15 http://fivedots.coe.psu.ac.th/~ad/jg/ch9/ 16 -------------------- 17 Usage:

compile *.java run MultiNyAR

18 */

19 import java.awt.*; 20 import java.io.*; 21 import javax.swing.*;

22 import com.sun.j3d.utils.universe.*; 23 import com.sun.j3d.utils.geometry.*; 24 import javax.media.j3d.*; 25 import javax.vecmath.*;

26 import jp.nyatla.nyartoolkit.core.*; 27 import jp.nyatla.nyartoolkit.java3d.utils.*; 28 import jp.nyatla.nyartoolkit.NyARException;

29 public class MultiNyAR extends JFrame 30 { 31 private final String PARAMS_FNM = "C:/Documents and

Settings/Administrador/Mis documentos/NetBeansProjects/Nyar_netbeans/src/Data/camera_para.dat";

32 private static final int PWIDTH = 640; // size of panel 33 private static final int PHEIGHT = 480;

34 private static final double SHAPE_SIZE = 0.02;

35 private static final int BOUNDSIZE = 500; // larger than world

36 private J3dNyARParam cameraParams; 37 private JTextArea statusTA;

38 public MultiNyAR() 39 { 40 super("Multiple markers NyARToolkit Example");

41 cameraParams = readCameraParams(PARAMS_FNM);

42 Container cp = getContentPane();

43 // create a JPanel in the center of JFrame 44 JPanel p = new JPanel(); 45 p.setLayout( new BorderLayout() ); 46 p.setPreferredSize( new Dimension(PWIDTH, PHEIGHT) ); 47 cp.add(p, BorderLayout.CENTER);

48 // put the 3D canvas inside the JPanel 49 p.add(createCanvas3D(), BorderLayout.CENTER);

50 // add status field to bottom of JFrame 51 statusTA = new JTextArea(7, 10); // updated by

DetectMarkers object (see createSceneGraph()) 52 statusTA.setEditable(false);

53 cp.add(statusTA, BorderLayout.SOUTH);

54 // configure the JFrame 55 setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE )

; 56 pack(); 57 setVisible(true); 58 } // end of MultiNyAR() 59 private J3dNyARParam readCameraParams(String fnm) 60 { 61 J3dNyARParam cameraParams = null; 62 try { 63 cameraParams = new J3dNyARParam(); 64 cameraParams.loadARParamFromFile(fnm); 65 cameraParams.changeScreenSize(PWIDTH, PHEIGHT); 66 } 67 catch(NyARException e) 68 { System.out.println("Could not read camera parameters from "

+ fnm); 69 System.exit(1); 70 } 71 return cameraParams; 72 } // end of readCameraParams()

73 private Canvas3D createCanvas3D() 74 /* Build a 3D canvas for a Universe which contains 75 the 3D scene and view 76 univ --> locale --> scene BG

| ---> view BG --> Canvas3D (set up using camera cameraParams)

77 */ 78 { 79 Locale locale = new Locale( new VirtualUniverse() ); 80 locale.addBranchGraph( createSceneGraph() ); // add the

scene

81 // get the preferred graphics configuration for the default screen

82 GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();

83 Canvas3D c3d = new Canvas3D(config); 84 locale.addBranchGraph( createView(c3d) ); // add view branch

85 return c3d; 86 } // end of createCanvas3D()

87 private BranchGroup createSceneGraph() 88 /* The scene graph: 89 sceneBG 90 ---> lights 91 | 92 ---> bg 93 | 94 -----> tg1 ---> model1 95 -----> tg2 ---> model2 96 | 97 ---> behavior (controls the bg and the tg's of the models) 98 */ 99 { 100 BranchGroup sceneBG = new BranchGroup(); 101 lightScene(sceneBG); // add lights

102 Background bg = makeBackground(); 103 sceneBG.addChild(bg); // add background

104 DetectMarkers detectMarkers = new DetectMarkers(this);

105 // the "hiro" marker uses a robot model, scaled by 0.15 units,

with no coords file 106 MarkerModel mm1 = new MarkerModel("patt.hiro",

"modelo4.3ds", 0.15, false); 107 if (mm1.getMarkerInfo() != null) { // creation was successful 108 sceneBG.addChild( mm1.getMoveTg() );

Page 22: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

21

109 detectMarkers.addMarker(mm1); 110 }

111 // the "kanji" marker uses a cow model, scaled by 0.12 units,

with coords file 112 MarkerModel mm2 = new MarkerModel("patt.kanji",

"modelo3.3ds", 0.15, true); 113 if (mm2.getMarkerInfo() != null) { 114 sceneBG.addChild( mm2.getMoveTg() ); 115 detectMarkers.addMarker(mm2); 116 }

117 MarkerModel mm3 = new MarkerModel("patt.3marker16",

"modelo2.3ds", 0.15, true); 118 if (mm3.getMarkerInfo() != null) { 119 sceneBG.addChild( mm3.getMoveTg() ); 120 detectMarkers.addMarker(mm3); 121 }

122 /* MarkerModel mm4 = new

MarkerModel("patt.4marker16", "modelo1.3ds", 0.15, true); 123 if (mm4.getMarkerInfo() != null) { 124 sceneBG.addChild( mm4.getMoveTg() ); 125 detectMarkers.addMarker(mm4); 126 }*/

127 MarkerModel mm5 = new MarkerModel("patt.5marker16",

"modelo1.3ds", 0.15, true); 128 if (mm5.getMarkerInfo() != null) { 129 sceneBG.addChild( mm5.getMoveTg() ); 130 detectMarkers.addMarker(mm5); 131 }

132 // create a NyAR multiple marker behaviour 133 sceneBG.addChild( new NyARMarkersBehavior(cameraParams,

bg, detectMarkers) );

134 sceneBG.compile(); // optimize the sceneBG graph 135 return sceneBG; 136 } // end of createSceneGraph()

137 private void lightScene(BranchGroup sceneBG) 138 /* One ambient light, 2 directional lights */ 139 { 140 Color3f white = new Color3f(1.0f, 1.0f, 1.0f); 141 BoundingSphere bounds = new BoundingSphere(new

Point3d(0,0,0), BOUNDSIZE);

142 // Set up the ambient light 143 AmbientLight ambientLightNode = new AmbientLight(white); 144 ambientLightNode.setInfluencingBounds(bounds); 145 sceneBG.addChild(ambientLightNode);

146 // Set up the directional lights 147 Vector3f light1Direction = new Vector3f(-1.0f, -1.0f, -1.0f); 148 // left, down, backwards 149 Vector3f light2Direction = new Vector3f(1.0f, -1.0f, 1.0f); 150 // right, down, forwards

151 DirectionalLight light1 = new DirectionalLight(white,

light1Direction); 152 light1.setInfluencingBounds(bounds); 153 sceneBG.addChild(light1);

154 DirectionalLight light2 = new DirectionalLight(white,

light2Direction);

155 light2.setInfluencingBounds(bounds); 156 sceneBG.addChild(light2); 157 } // end of lightScene()

158 private Background makeBackground() 159 // the background will be the current image captured by the

camera 160 { 161 Background bg = new Background(); 162 BoundingSphere bounds = new BoundingSphere(); 163 bounds.setRadius(10.0); 164 bg.setApplicationBounds(bounds); 165 bg.setImageScaleMode(Background.SCALE_FIT_ALL); 166 bg.setCapability(Background.ALLOW_IMAGE_WRITE); // so

can change image

167 return bg; 168 } // end of makeBackground()

169 private BranchGroup createView(Canvas3D c3d) 170 // create a view graph using the camera parameters 171 { 172 View view = new View(); 173 ViewPlatform viewPlatform = new ViewPlatform(); 174 view.attachViewPlatform(viewPlatform); 175 view.addCanvas3D(c3d);

176 view.setPhysicalBody(new PhysicalBody()); 177 view.setPhysicalEnvironment(new PhysicalEnvironment());

178 view.setCompatibilityModeEnable(true); 179 view.setProjectionPolicy(View.PERSPECTIVE_PROJECTION); 180 view.setLeftProjection( cameraParams.getCameraTransform() )

; // camera projection

181 TransformGroup viewGroup = new TransformGroup(); 182 Transform3D viewTransform = new Transform3D(); 183 viewTransform.rotY(Math.PI); // rotate 180 degrees 184 viewTransform.setTranslation(new Vector3d(0.0, 0.0, 0.0)); //

start at origin 185 viewGroup.setTransform(viewTransform); 186 viewGroup.addChild(viewPlatform);

187 BranchGroup viewBG = new BranchGroup(); 188 viewBG.addChild(viewGroup);

189 return viewBG; 190 } // end of createView()

191 public void setStatus(String msg) 192 // called from DetectMarkers 193 { 194 statusTA.setText(msg); 195 } // end of setStatus()

196 // ------------------------------------------------------------

197 public static void main(String args[]) 198 { new MultiNyAR(); }

199 } // end of MultiNyAR class

Page 23: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

22

Anexo 2.

Clase MarkerModel.java

1. // MarkerModel.java 2. // Andrew Davison, [email protected], April 2010

3. /* Holds NyARToolkit marker information and the Java3D scene

graph for its 4. associated model.

5. The model is loaded using the PropManager class, which is

described in Chapter 16 6. of "Killer Game Programming in Java"

(http://fivedots.coe.psu.ac.th/~ad/jg/ch9/) 7. */

8. import java.util.*;

9. import javax.media.j3d.*; 10. import javax.vecmath.*;

11. import jp.nyatla.nyartoolkit.java3d.utils.*;

12. import jp.nyatla.nyartoolkit.NyARException; 13. import jp.nyatla.nyartoolkit.core.*; 14. import jp.nyatla.nyartoolkit.core.param.NyARParam; 15. import

jp.nyatla.nyartoolkit.core.transmat.NyARTransMatResult; 16. import jp.nyatla.nyartoolkit.detector.*; 17. import jp.nyatla.nyartoolkit.core.types.*;

18. public class MarkerModel 19. { 20. private final String MARKER_DIR = "C:/Documents and

Settings/Administrador/Mis documentos/NetBeansProjects/Nyar_netbeans/src/Data/";

21. private final double MARKER_SIZE = 0.095; // 95 cm width and height in Java 3D world units

22. private String markerName, modelName; 23. private NyARCode markerInfo = null; // NYArToolkit marker

details

24. private TransformGroup moveTg; // for moving the marker model

25. private Switch visSwitch; // for changing the model's

visibility 26. private boolean isVisible;

27. private SmoothMatrix sMat; // for smoothing the

transforms applied to the model

28. // details about a model's position and orientation (in degrees) 29. private Point3d posInfo = null; 30. private Point3d rotsInfo = null;

31. private int numTimesLost = 0; // number of times marker for

this model not detected

32. public MarkerModel(String markerFnm, String modelFnm, double scale, boolean hasCoords)

33. { 34. markerName = markerFnm; 35. modelName = modelFnm.substring(0,

modelFnm.lastIndexOf('.')); // remove filename extension

36. // build a branch for the model: TG --> Switch --> TG --> model

37. // load the model, with scale and coords info 38. TransformGroup modelTG = loadModel(modelFnm, scale,

hasCoords);

39. // create switch for model visibility 40. visSwitch = new Switch();

41. visSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE); 42. visSwitch.addChild( modelTG ); 43. visSwitch.setWhichChild( Switch.CHILD_NONE ); // make

invisible 44. isVisible = false;

45. // create transform group for positioning the model 46. moveTg = new TransformGroup(); 47. moveTg.setCapability(TransformGroup.ALLOW_TRANSFORM_

WRITE); // so this tg can change 48. moveTg.addChild(visSwitch);

49. // load marker info 50. try { 51. markerInfo = new NyARCode(16,16); // default integer width,

height 52. markerInfo.loadARPattFromFile(MARKER_DIR+markerName);

// load marker image 53. } 54. catch(NyARException e) 55. { System.out.println(e); 56. markerInfo = null; 57. }

58. sMat = new SmoothMatrix(); 59. } // end of MarkerModel()

60. private TransformGroup loadModel(String modelFnm, double scale, boolean hasCoords)

61. // load the model, rotating and scaling it 62. { 63. PropManager propMan = new PropManager(modelFnm,

hasCoords);

64. // get the TG for the prop (model) 65. TransformGroup propTG = propMan.getTG();

66. // rotate and scale the prop 67. Transform3D modelT3d = new Transform3D(); 68. modelT3d.rotX( Math.PI/2.0 ); 69. // the prop lies flat on the marker; rotate forwards 90 degrees

so it is standing 70. Vector3d scaleVec = calcScaleFactor(propTG, scale); // scale

the prop 71. modelT3d.setScale( scaleVec );

72. TransformGroup modelTG = new TransformGroup(modelT3d); 73. modelTG.addChild(propTG);

74. return modelTG; 75. } // end of loadModel()

76. private Vector3d calcScaleFactor(TransformGroup modelTG, double scale)

77. // Scale the prop based on its original bounding box size 78. { 79. BoundingBox boundbox = new

BoundingBox( modelTG.getBounds() ); 80. System.out.println(boundbox);

81. // obtain the upper and lower coordinates of the box 82. Point3d lower = new Point3d(); 83. boundbox.getLower( lower ); 84. Point3d upper = new Point3d(); 85. boundbox.getUpper( upper );

86. // store the largest X, Y, or Z dimension and calculate a scale

factor 87. double max = 0.0; 88. if( Math.abs(upper.x - lower.x) > max) 89. max = Math.abs(upper.x - lower.x);

90. if( Math.abs(upper.y - lower.y) > max)

Page 24: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

23

91. max = Math.abs(upper.y - lower.y);

92. if( Math.abs(upper.z - lower.z) > max) 93. max = Math.abs(upper.z - lower.z);

94. double scaleFactor = scale/max; 95. System.out.printf("max dimension: %.3f; scale factor: %.3f\n",

max, scaleFactor);

96. // limit the scaling so that a big model isn't scaled too much 97. if( scaleFactor < 0.0005 ) 98. scaleFactor = 0.0005;

99. return new Vector3d(scaleFactor, scaleFactor, scaleFactor); 100. } // end of calcScaleFactor()

101. public String getNameInfo() 102. { return markerName + " / " + modelName; }

103. public NyARCode getMarkerInfo() 104. { return markerInfo; }

105. public double getMarkerWidth() 106. { // System.out.println("Width: " + markerInfo.getWidth()); 107. return MARKER_SIZE; // markerInfo.getWidth() not valid

since requires Java 3D units 108. }

109. public TransformGroup getMoveTg() 110. { return moveTg; }

111. public void moveModel(NyARTransMatResult transMat) 112. // detected marker so update model's moveTG 113. { 114. visSwitch.setWhichChild( Switch.CHILD_ALL ); // make visible 115. isVisible = true;

116. sMat.add(transMat);

117. Matrix4d mat = sMat.get(); 118. Transform3D t3d = new Transform3D(mat);

119. int flags = t3d.getType(); 120. if ((flags & Transform3D.AFFINE) == 0) 121. System.out.println("Ignoring non-affine transformation"); 122. else { 123. if (moveTg != null) 124. moveTg.setTransform(t3d);

125. // System.out.println("transformation matrix: " + mat); 126. calcPosition(mat); 127. calcEulerRots(mat); 128. } 129. } // end of moveModel()

130. private void calcPosition(Matrix4d mat) 131. // extract the (x,y,z) position vals stored in the matrix 132. { 133. // convert to cm and round 134. double x = roundToNumPlaces( mat.getElement(0,3)*100, 1); 135. double y = roundToNumPlaces( mat.getElement(1,3)*100, 1); 136. double z = roundToNumPlaces( mat.getElement(2,3)*100, 1); 137. // System.out.println(getNameInfo() + " (" + x + ", " + y + ", " + z

+ ")"); 138. posInfo = new Point3d(x, y, z); 139. } // end of reportPosition()

140. private double roundToNumPlaces(double val, int numPlaces) 141. { 142. double power = Math.pow(10, numPlaces); 143. long temp = Math.round(val*power); 144. return ((double)temp)/power; 145. }

146. public Point3d getPos() 147. { return posInfo; }

148. private void calcEulerRots(Matrix4d mat) 149. /* calculate the Euler rotation angles from the upper 3x3

rotation 150. components of the 4x4 transformation matrix. 151. Based on code by Daniel Selman, December 1999 152. which is based on pseudo-code in "Matrix and Quaternion FAQ",

Q37 153. http://www.j3d.org/matrix_faq/matrfaq_latest.html 154. */ 155. { 156. rotsInfo = new Point3d();

157. rotsInfo.y = -Math.asin(mat.getElement(2,0)); 158. double c = Math.cos(rotsInfo.y);

159. double tRx, tRy, tRz; 160. if(Math.abs(rotsInfo.y) > 0.00001) { 161. tRx = mat.getElement(2,2)/c; 162. tRy = -mat.getElement(2,1)/c; 163. rotsInfo.x = Math.atan2(tRy, tRx);

164. tRx = mat.getElement(0,0)/c; 165. tRy = -mat.getElement(1,0)/c; 166. rotsInfo.z = Math.atan2(tRy, tRx); 167. } 168. else { 169. rotsInfo.x = 0.0;

170. tRx = mat.getElement(1,1); 171. tRy = mat.getElement(0,1); 172. rotsInfo.z = Math.atan2(tRy, tRx); 173. }

174. rotsInfo.x = -rotsInfo.x; 175. rotsInfo.z = -rotsInfo.z;

176. // ensure the values are positive by adding 2*PI if necessary... 177. if(rotsInfo.x < 0.0) 178. rotsInfo.x += 2*Math.PI;

179. if(rotsInfo.y < 0.0) 180. rotsInfo.y += 2*Math.PI;

181. if(rotsInfo.z < 0.0) 182. rotsInfo.z += 2*Math.PI;

183. // convert to degrees and round 184. rotsInfo.x = roundToNumPlaces( Math.toDegrees(rotsInfo.x),

0); 185. rotsInfo.y = roundToNumPlaces( Math.toDegrees(rotsInfo.y),

0); 186. rotsInfo.z = roundToNumPlaces( Math.toDegrees(rotsInfo.z),

0);

187. // System.out.println(getNameInfo() + " rots (" + 188. // rotsInfo.x + ", " + rotsInfo.y + ", " + rotsInfo.z + ")"); 189. } // end of calcEulerRots()

190. public Point3d getRots() 191. { return rotsInfo; }

192. public void resetNumTimesLost() 193. { numTimesLost = 0; }

194. public void incrNumTimesLost() 195. { numTimesLost++; }

196. public int getNumTimesLost() 197. { return numTimesLost; }

198. public void hideModel() 199. { 200. visSwitch.setWhichChild( Switch.CHILD_NONE ); // make

model invisible 201. isVisible = false; 202. } 203. public boolean isVisible() 204. { return isVisible; }

205. } // end of MarkerModel class

Page 25: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

24

Anexo 3.

Clase DetectMarkers.java

1. // DetectMarkers.java 2. // Andrew Davison, [email protected], April 2010

3. /* Collection of MarkerModel objects and a detector that finds 4. markers in the camera's captured image. The new marker

position 5. is used to move its corresponding model 6. */

7. import java.util.*;

8. import javax.media.j3d.*; 9. import javax.vecmath.*;

10. import jp.nyatla.nyartoolkit.java3d.utils.*;

11. import jp.nyatla.nyartoolkit.NyARException; 12. import jp.nyatla.nyartoolkit.core.*; 13. import jp.nyatla.nyartoolkit.core.param.NyARParam; 14. import

jp.nyatla.nyartoolkit.core.transmat.NyARTransMatResult; 15. import jp.nyatla.nyartoolkit.detector.*; 16. import jp.nyatla.nyartoolkit.core.types.*;

17. public class DetectMarkers 18. { 19. private final static double MIN_CONF = 0.3; 20. // smallest confidence accepted for finding a marker

21. private final static int CONF_SIZE = 1000; 22. // for converting confidence level double <--> integer

23. private final static int MAX_NO_DETECTIONS = 50; 24. // number of times a marker goes undetected before being

made invisible

25. private ArrayList<MarkerModel> markerModels; 26. private int numMarkers;

27. private MultiNyAR top; // for reporting status 28. private NyARDetectMarker detector;

29. private NyARTransMatResult transMat = new

NyARTransMatResult(); 30. // transformation matrix for a marker, which is used to move

its model

31. public DetectMarkers(MultiNyAR top) 32. { 33. this.top = top; 34. markerModels = new ArrayList<MarkerModel>(); 35. numMarkers = 0; 36. } // end of DetectMarkers()

37. public void addMarker(MarkerModel mm) 38. { 39. markerModels.add(numMarkers, mm); // add to end of list 40. numMarkers++; 41. }

42. public void createDetector(NyARParam params, J3dNyARRaster_RGB rasterRGB)

43. // create a single detector for all the markers 44. { 45. NyARCode[] markersInfo = new NyARCode[numMarkers];

46. double[] widths = new double[numMarkers]; 47. int i = 0; 48. for (MarkerModel mm : markerModels) { 49. markersInfo[i] = mm.getMarkerInfo(); 50. widths[i] = mm.getMarkerWidth(); 51. // System.out.println("Object " + i + ": marker info = " +

markersInfo[i]); 52. i++; 53. }

54. try { 55. detector = new NyARDetectMarker(params, markersInfo,

widths, numMarkers, i. rasterRGB.getBufferReader().getBufferTy

pe()); 56. detector.setContinueMode(false); // no history stored; use

SmoothMatrix instead 57. } 58. catch(NyARException e) 59. { System.out.println("Could not create markers detector"); 60. System.exit(1); 61. } 62. } // end of createDetector()

63. public void updateModels(J3dNyARRaster_RGB rasterRGB) 64. // move marker models using the detected marker positions

inside the raster 65. { 66. int numDetections = getNumDetections(detector, rasterRGB); 67. // System.out.println("numDetections: " + numDetections);

68. try { 69. StringBuffer statusInfo = new StringBuffer(); // for holding

status information

70. // find the best detected match for each marker 71. for (int mkIdx = 0; mkIdx < numMarkers; mkIdx++) { 72. MarkerModel mm = markerModels.get(mkIdx);

73. int[] detectInfo = findBestDetectedIdx(detector, numDetections,

mkIdx); // look for mkIdx 74. int bestDetectedIdx = detectInfo[0]; 75. double confidence = ((double)detectInfo[1])/CONF_SIZE; //

convert back to double

76. if (bestDetectedIdx == -1) // marker not found so incr numTimesLost

77. mm.incrNumTimesLost(); 78. else { // marker found 79. if (confidence >= MIN_CONF) { // detected a marker for mkIdx

with high confidence 80. mm.resetNumTimesLost(); 81. // apply the transformation from the detected marker to the

marker's model 82. // System.out.println(" For markers list index " + mkIdx + 83. // ": best detected index = " + bestDetectedIdx); 84. detector.getTransmationMatrix(bestDetectedIdx, transMat); 85. if (transMat.has_value) 86. mm.moveModel(transMat); 87. else 88. System.out.println("Problem with transformation matrix"); 89. } 90. // else // found a marker, but with low confidence 91. // System.out.println(" ***** " + mkIdx + " conf: " +

confidence); 92. }

93. if (mm.getNumTimesLost() > MAX_NO_DETECTIONS) //

marker not detected too many times 94. mm.hideModel(); // make its model invisible

95. statusInfo.append(mkIdx + ". " + mm.getNameInfo() + " (" +

confidence + ")\n"); 96. addToStatusInfo(mm, statusInfo);

Page 26: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

25

97. } 98. top.setStatus( statusInfo.toString()); // display marker models

status in the GUI 99. } 100. catch(NyARException e) 101. { System.out.println(e); } 102. } // end of updateModels()

103. private int getNumDetections(NyARDetectMarker detector, J3dNyARRaster_RGB rasterRGB)

104. { 105. int numDetections = 0; 106. try { 107. synchronized (rasterRGB) { 108. if (rasterRGB.hasData()) 109. numDetections = detector.detectMarkerLite(rasterRGB, 100); 110. } 111. } 112. catch(NyARException e) 113. { System.out.println(e); }

114. return numDetections; 115. } // end of getNumDetections()

116. private int[] findBestDetectedIdx(NyARDetectMarker detector, int numDetections, int markerIdx)

117. /* return best detected marker index for marker markerIdx from all detected markers,

118. along with its confidence value as an integer */ 119. { 120. int iBest = -1; 121. double confBest = -1;

122. // System.out.println(" Look at detections for marker " +

markerIdx); 123. for (int i = 0; i < numDetections; i++) { // check all detected

markers 124. int codesIdx = detector.getARCodeIndex(i);

125. double conf = detector.getConfidence(i); 126. // System.out.println(" detections index["+i+"] = code index "

+ codesIdx + " -- conf: " + conf);

127. if ((codesIdx == markerIdx) && (conf > confBest)) { 128. iBest = i; // detected marker index with highest confidence 129. confBest = conf; 130. } 131. } 132. // System.out.println(" mark index "+ markerIdx+" iBest = " +

iBest + " conf: " + confBest);

133. int[] detectInfo = {iBest, (int)(confBest*CONF_SIZE)}; 134. return detectInfo; 135. } // end of findBestDetectedIdx()

136. private void addToStatusInfo(MarkerModel mm, StringBuffer statusInfo)

137. // add details about MarkerModel object to status info string 138. { 139. if (!mm.isVisible()) 140. statusInfo.append(" not visible\n"); 141. else { // model is visible, so report position and orientation 142. Point3d pos = mm.getPos(); 143. if (pos != null) 144. statusInfo.append(" at (" + pos.x + ", " + pos.y + ", " + pos.z +

")\n"); 145. else 146. statusInfo.append(" at an unknown position\n");

147. Point3d rots = mm.getRots(); 148. if (rots != null) 149. statusInfo.append(" rots (" + rots.x + ", " + rots.y + ", " + rots.z

+ ")\n"); 150. else 151. statusInfo.append(" with unknown rotations\n"); 152. } 153. } // end of addToStatusInfo()

154. } // end of class DetectMarkers

Page 27: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

26

Anexo 4.

Clase PropManager.java1. // PropManager.java 2. // Andrew Davison, January 2003, [email protected]

3. /* The user supplies the name of a 3D object file to be loaded. 4. Its bounding sphere is automatically scaled to have a radius 5. of 1 unit, and rotated -90 around x-axis if it is a 3ds model.

6. A large range of different 3D object formats can be loaded 7. since we are using the Portfolio loaders.

8. Once loaded, the image can be moved and rotated along the 9. X, Y, and Z axes, and scaled. The resulting position, 10. rotation, and scaling information can be stored in a 11. 'coords' file (which has the same name as the 3D file 12. + "Coords.txt").

13. The rotation information is stored as a series of rotation 14. *numbers* which must be executed in order to get to the curent 15. overall rotation: 16. 1 = positive ROT_INCR around x-axis 17. 2 = negative ROT_INCR around x-axis

18. 3 = positive ROT_INCR around y-axis 19. 4 = negative ROT_INCR around y-axis

20. 5 = positive ROT_INCR around z-axis 21. 6 = negative ROT_INCR around z-axis

22. This approach is used to try to avoid the problem that a mix of 23. rotations about diffrent axes do not produce the same result if 24. carried out in different orders.

25. The coordinates information can be loaded along with the

object 26. by using:

i. java Loader3D -c <3D filename>

27. The loaded object is hung off several TGs, and the top one can be

28. accessed by calling getTG().

29. Changes: - removed use of j3d-fly VRML loader and starfire 3DS

loader

30. April 2010 - fixed rotInfo generic typing - used Java3D's ObjectFile to load wavefront files so

material is correct 31. */

32. import java.util.*; 33. import java.io.*; 34. import java.text.DecimalFormat;

35. import javax.media.j3d.*; 36. import javax.vecmath.*; 37. import com.sun.j3d.loaders.*; 38. import com.sun.j3d.loaders.objectfile.ObjectFile;

39. // Portfolio loader packages 40. import ncsa.j3d.*; 41. import ncsa.j3d.loaders.*; 42. // NCSA Portfolio is available at

http://fivedots.coe.psu.ac.th/~ad/jg/ch9/

43. public class PropManager 44. { 45. // for specifying moves and rotations 46. private static final int X_AXIS = 0; 47. private static final int Y_AXIS = 1; 48. private static final int Z_AXIS = 2; 49. private static final int INCR = 0; 50. private static final int DECR = 1;

51. private static final double MOVE_INCR = 0.1; // move increment for an object

52. private static final double ROT_INCR = 10; // rotation increment (in degrees)

53. private static final double ROT_AMT = Math.toRadians(ROT_INCR); // in radians

54. // TGs which the loaded object (the prop) hangs off: 55. // moveTG-->rotTG-->scaleTG-->objBoundsTG-->obj 56. private TransformGroup moveTG, rotTG, scaleTG; 57. private Transform3D t3d; // for accessing a TG's

transform 58. private Transform3D chgT3d; // holds current change to

the posn, rot, or scale

59. private String filename; // of loaded object 60. private double xRot, yRot, zRot; // total of rotation angles

carried out 61. private ArrayList<Integer> rotInfo; // stores the sequence

of rotation numbers 62. private double scale; // current object scaling

63. private DecimalFormat df; // for debugging

64. public PropManager(String loadFnm, boolean hasCoordsInfo) 65. { 66. filename = loadFnm; 67. xRot = 0.0; yRot = 0.0; zRot = 0.0; // initial loaded object

settings 68. rotInfo = new ArrayList<Integer>(); 69. scale = 1.0;

70. t3d = new Transform3D(); // setup reusable Transform3D

objects 71. chgT3d = new Transform3D();

72. df = new DecimalFormat("0.###"); // 3 dp

73. loadFile(loadFnm); 74. if (hasCoordsInfo) // load in coords info also 75. getFileCoords(loadFnm); 76. } // end of PropManager()

77. private void loadFile(String fnm) 78. /* The 3D object file is loaded using a Portfolio loader.

79. The loaded object has 4 transform groups above it --

objBoundsTG is 80. for adjusting the object's bounded sphere so it is centered at 81. (0,0,0) and has unit radius.

82. The other TGs are for doing separate moves, rotations, and

scaling 83. of the object. 84. moveTG-->rotTG-->scaleTG-->objBoundsTG-->object 85. */ 86. { System.out.println("Loading model file: models/" + fnm);

87. String ext = getExtension(fnm); 88. Scene s = null; 89. try { 90. if (ext.equals("obj")) { // the file is a wavefront model 91. // System.out.println("Loading obj file"); 92. ObjectFile of = new ObjectFile (); 93. of.setFlags(ObjectFile.RESIZE | ObjectFile.TRIANGULATE |

ObjectFile.STRIPIFY); 94. s = of.load("C:/Documents and Settings/Administrador/Mis

documentos/NetBeansProjects/Nyar_netbeans/src/models/"+fnm);

95. } 96. else { // use Portfolio loader for other models 97. ModelLoader modelLoader = new ModelLoader();

Page 28: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

27

- s = modelLoader.load("C:/Documents and Settings/Administrador/Mis documentos/NetBeansProjects/Nyar_netbeans/src/models/"+fnm); // handles many types of file

- } 98. } 99. catch (Exception e) {

- System.err.println(e); - System.exit(1);

100. }

101. // get the branch group for the loaded object 102. BranchGroup sceneGroup = s.getSceneGroup();

103. // create a transform group for the object's bounding sphere 104. TransformGroup objBoundsTG = new TransformGroup(); 105. objBoundsTG.addChild( sceneGroup );

106. // resize loaded object's bounding sphere (and maybe rotate) 107. BoundingSphere objBounds = (BoundingSphere)

sceneGroup.getBounds(); 108. setBSPosn(objBoundsTG, objBounds.getRadius(), ext);

109. // create a transform group for scaling the object 110. scaleTG = new TransformGroup(); 111. scaleTG.setCapability(TransformGroup.ALLOW_TRANSFORM_R

EAD); 112. scaleTG.setCapability(TransformGroup.ALLOW_TRANSFORM_

WRITE); 113. scaleTG.addChild( objBoundsTG );

114. // create a transform group for rotating the object 115. rotTG = new TransformGroup(); 116. rotTG.setCapability(TransformGroup.ALLOW_TRANSFORM_RE

AD); 117. rotTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WR

ITE); 118. rotTG.addChild( scaleTG );

119. // create a transform group for moving the object 120. moveTG = new TransformGroup(); 121. moveTG.setCapability(TransformGroup.ALLOW_TRANSFORM_

READ); 122. moveTG.setCapability(TransformGroup.ALLOW_TRANSFORM_

WRITE); 123. moveTG.addChild( rotTG );

124. } // end of loadFile()

125. private String getExtension(String fnm) 126. // return the extension of fnm, or "(none)" 127. { 128. int dotposn = fnm.lastIndexOf("."); 129. if (dotposn == -1) // no extension 130. return "(none)"; 131. else 132. return fnm.substring(dotposn+1).toLowerCase(); 133. }

134. private void setBSPosn(TransformGroup objBoundsTG, i. double

radius, String ext)

135. // Scale the object to unit radius, and rotate -90 around x-axis if the

136. // file contains a 3ds model 137. { 138. Transform3D objectTrans = new Transform3D(); 139. objBoundsTG.getTransform( objectTrans );

140. // System.out.println("radius: " + df.format(radius));

141. // scale the object so its bounds are within a 1 unit radius

sphere 142. Transform3D scaleTrans = new Transform3D(); 143. double scaleFactor = 1.0/radius; 144. // System.out.println("scaleFactor: " + df.format(scaleFactor) ); 145. scaleTrans.setScale( scaleFactor );

146. // final transform = [original] * [scale] (and possible *[rotate]) 147. objectTrans.mul(scaleTrans);

148. if (ext.equals("3ds")) { // the file is a 3ds model 149. // System.out.println("Rotating -90 around x-axis"); 150. Transform3D rotTrans = new Transform3D(); 151. rotTrans.rotX( -Math.PI/2.0 ); // 3ds models are often on

their face; fix that 152. objectTrans.mul(rotTrans); 153. }

154. objBoundsTG.setTransform(objectTrans); 155. } // end of setBSPosn()

156. public TransformGroup getTG() 157. // used by WrapLoader3D to add object to 3D world 158. { return moveTG; }

159. // ---------------------------------------------------------------- 160. // obtain coords file info and apply it to the loaded object

161. private void getFileCoords(String fnm) 162. /* Obtain coords info from the coordinates file for fnm. 163. The coords file has the format: 164. <3D object fnm> 165. [-p px py pz] 166. [-r sequence of numbers] 167. [-s scale] 168. */ 169. { 170. String coordFile = "C:/Documents and

Settings/Administrador/Mis documentos/NetBeansProjects/Nyar_netbeans/src/models/" + getName(fnm) + "Coords.txt";

171. try { 172. BufferedReader br = new BufferedReader( new

FileReader(coordFile)); 173. br.readLine(); // skip fnm line (we know this already) 174. String line; 175. char ch; 176. while((line = br.readLine()) != null) { 177. ch = line.charAt(1); 178. if (ch == 'p') 179. setCurrentPosn(line); 180. else if (ch == 'r') 181. setCurrentRotation(line); 182. else if (ch == 's') 183. setCurrentScale(line); 184. else 185. System.out.println(coordFile + ": did not recognise line: " +

line); 186. } 187. br.close(); 188. System.out.println("Read in coords file: " + coordFile); 189. } 190. catch (IOException e) 191. { System.out.println("Error reading coords file: " + coordFile); 192. System.exit(1); 193. } 194. } // end of getFileCoords()

195. private String getName(String fnm) 196. // extract name before the final '.' suffix 197. { 198. int dotposn = fnm.lastIndexOf("."); 199. if (dotposn == -1) // no extension 200. return fnm; 201. else 202. return fnm.substring(0, dotposn); 203. }

204. private void setCurrentPosn(String line) 205. // extract the (x,y,z) position info from the coords file,

Page 29: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

28

206. // then apply it to the loaded object 207. { 208. double vals[] = new double[3]; // for the position data 209. vals[0] = 0; vals[1] = 0; vals[2] = 0; // represents (x,y,z)

210. StringTokenizer tokens = new StringTokenizer(line); 211. String token = tokens.nextToken(); // skip command label 212. int count = 0; 213. while (tokens.hasMoreTokens()) { 214. token = tokens.nextToken(); 215. try { 216. vals[count] = Double.parseDouble(token); 217. count++; 218. } 219. catch (NumberFormatException ex){ 220. System.out.println("Incorrect format for position data in coords

file"); 221. break; 222. } 223. } 224. if (count != 3) 225. System.out.println("Insufficient position data in coords file");

226. // apply the moves to the loaded object 227. doMove( new Vector3d( vals[0], vals[1], vals[2]) );

228. } // end of setCurrentPosn()

229. private void setCurrentRotation(String line) 230. // extract the rotation info from the coords file, 231. // and apply it to the loaded object 232. { 233. int rotNum; 234. StringTokenizer tokens = new StringTokenizer(line); 235. String token = tokens.nextToken(); // skip command label 236. if (!tokens.hasMoreTokens()) // there may not be any rotation

numbers 237. return; 238. token = tokens.nextToken(); 239. for (int i=0; i < token.length(); i++) { 240. try { 241. rotNum = Character.digit(token.charAt(i),10); 242. // rotInfo.add( new Integer(rotNum)); 243. } 244. catch (NumberFormatException ex){ 245. System.out.println("Incorrect format for rotation data in coords

file"); 246. break; 247. } 248. if (rotNum == 1) // positive x-axis rotation 249. rotate(X_AXIS, INCR); 250. else if (rotNum == 2) // negative 251. rotate(X_AXIS, DECR); 252. else if (rotNum == 3) // positive y-axis rotation 253. rotate(Y_AXIS, INCR); 254. else if (rotNum == 4) // negative 255. rotate(Y_AXIS, DECR); 256. else if (rotNum == 5) // positive z-axis rotation 257. rotate(Z_AXIS, INCR); 258. else if (rotNum == 6) // negative 259. rotate(Z_AXIS, DECR); 260. else 261. System.out.println("Did not recognise the rotation info in the

coords file"); 262. } 263. } // end of setCurrentRotation()

264. private void setCurrentScale(String line) 265. // extract the scale info from the coords file, 266. // and apply it to the loaded object 267. { 268. StringTokenizer tokens = new StringTokenizer(line); 269. String token = tokens.nextToken(); // skip command label 270. double startScale;

271. token = tokens.nextToken(); // should be the scale value 272. try { 273. startScale = Double.parseDouble(token); 274. } 275. catch (NumberFormatException ex){ 276. System.out.println("Incorrect format for scale data in coords

file"); 277. startScale = 1.0; 278. } 279. // System.out.println("Loaded start scale: " + startScale); 280. if (startScale != 1.0) { 281. scale(startScale); 282. } 283. } // end of setCurrentScale()

284. //--------------------------------------------------------- 285. // modify the position/rotation/scale of the loaded object

286. /* These methods are called when applying the coords file 287. information *and* when user commands sent from the GUI 288. are being processed. 289. */

290. public void move(int axis, int change) 291. // move the object along an axis 292. { 293. double moveStep = (change == INCR) ? MOVE_INCR : -

MOVE_INCR ; 294. Vector3d moveVec; 295. if (axis == X_AXIS) 296. moveVec = new Vector3d(moveStep,0,0); 297. else if (axis == Y_AXIS) 298. moveVec = new Vector3d(0,moveStep,0); 299. else // Z_AXIS 300. moveVec = new Vector3d(0,0,moveStep); 301. doMove( moveVec ); 302. } // end of move()

303. private void doMove(Vector3d theMove) 304. // move the object by theMove amount 305. { 306. moveTG.getTransform(t3d); // get current position from TG 307. chgT3d.setIdentity(); // reset change Trans 308. chgT3d.setTranslation(theMove); // setup move 309. t3d.mul(chgT3d); // 'add' move to current position 310. moveTG.setTransform(t3d); // update TG 311. } // end of doMove()

312. public void rotate(int axis, int change) 313. // rotate the object about an axis, and remember the change 314. { 315. doRotate(axis, change); 316. storeRotate(axis, change); 317. } // end of rotate()

318. private void doRotate(int axis, int change) 319. // rotate the object about the axis by radians amount 320. { 321. double radians = (change == INCR) ? ROT_AMT : -ROT_AMT; 322. rotTG.getTransform(t3d); // get current rotation from TG 323. chgT3d.setIdentity(); // reset change Trans 324. switch (axis) { // setup new rotation 325. case X_AXIS: chgT3d.rotX(radians); break; 326. case Y_AXIS: chgT3d.rotY(radians); break; 327. case Z_AXIS: chgT3d.rotZ(radians); break; 328. default: System.out.println("Unknown axis of rotation"); break; 329. } 330. t3d.mul(chgT3d); // 'add' new rotation to current one 331. rotTG.setTransform(t3d); // update the TG 332. } // end of doRotate()

333. private void storeRotate(int axis, int change)

Page 30: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

29

334. // store the rotation information 335. { 336. double degrees = (change == INCR) ? ROT_INCR : -ROT_INCR; 337. switch (axis) { 338. case X_AXIS: storeRotateX(degrees); break; 339. case Y_AXIS: storeRotateY(degrees); break; 340. case Z_AXIS: storeRotateZ(degrees); break; 341. default: System.out.println("Unknown storage axis of

rotation"); break; 342. } 343. } // end of storeRotate()

344. private void storeRotateX(double degrees) 345. // record the x-axis rotation 346. { 347. xRot = (xRot+degrees)%360; // update x-axis total rotation 348. if (degrees == ROT_INCR) 349. rotInfo.add(new Integer(1)); // rotation number 350. else if (degrees == -ROT_INCR) 351. rotInfo.add(new Integer(2)); 352. else 353. System.out.println("No X-axis rotation number for " + degrees); 354. } // end of storeRotateX()

355. private void storeRotateY(double degrees) 356. // record the y-axis rotation 357. { 358. yRot = (yRot+degrees)%360; // update y-axis total rotation 359. if (degrees == ROT_INCR) 360. rotInfo.add(new Integer(3)); // rotation number 361. else if (degrees == -ROT_INCR) 362. rotInfo.add(new Integer(4)); 363. else 364. System.out.println("No Y-axis rotation number for " + degrees); 365. } // end of storeRotateY()

366. private void storeRotateZ(double degrees) 367. // record the z-axis rotation 368. { 369. zRot = (zRot+degrees)%360; // update z-axis total rotation 370. if (degrees == ROT_INCR) 371. rotInfo.add(new Integer(5)); // rotation number 372. else if (degrees == -ROT_INCR) 373. rotInfo.add(new Integer(6)); 374. else 375. System.out.println("No Z-axis rotation number for " + degrees); 376. } // end of storeRotateZ()

377. public void scale(double d) 378. // Scale the object by d units 379. { 380. scaleTG.getTransform(t3d); // get current scale from TG 381. chgT3d.setIdentity(); // reset change Trans 382. chgT3d.setScale(d); // set up new scale 383. t3d.mul(chgT3d); // multiply new scale to current one 384. scaleTG.setTransform(t3d); // update the TG

385. scale *= d; // update scale variable 386. } // end of scale()

387. // ---------------------------------------------------------- 388. // return current position/rotation/scale information 389. // Used by the GUI interface

390. public Vector3d getLoc() 391. { 392. moveTG.getTransform(t3d); 393. Vector3d trans = new Vector3d(); 394. t3d.get(trans);

395. // printTuple(trans, "getLoc"); 396. return trans; 397. } // end of getLoc()

398. public Point3d getRotations() 399. { return new Point3d(xRot, yRot, zRot); }

400. public double getScale() 401. { return scale; }

402. // ------------------------------ storing ---------------------------

403. public void saveCoordFile() 404. // create a coords file for this object 405. { 406. String coordFnm = "C:/Documents and

Settings/Administrador/Mis documentos/NetBeansProjects/Nyar_netbeans/src/models/" + getName(filename) + "Coords.txt";

407. try { 408. PrintWriter out = new PrintWriter( new

FileWriter(coordFnm));

409. out.println(filename); // object filename 410. Vector3d currLoc = getLoc(); 411. out.println("-p " + df.format(currLoc.x) + " " +

df.format(currLoc.y) + " " + df.format(currLoc.z) );

412. out.print("-r "); 413. for (int i=0; i < rotInfo.size(); i++) 414. out.print( ""+((Integer) rotInfo.get(i)).intValue() ); 415. out.println("");

416. out.println("-s " + df.format(scale) );

417. out.close(); 418. System.out.println("Saved to coord file: " + coordFnm); 419. } 420. catch(IOException e) 421. { System.out.println("Error writing to coord file: " +

coordFnm); } 422. } // end of saveCoordFile()

423. // --------------------- methods used for debugging --------------------------

424. private void printTG(TransformGroup tg, String id) 425. // print the translation stored in tg 426. { 427. Transform3D currt3d = new Transform3D( ); 428. tg.getTransform( currt3d ); 429. Vector3d currTrans = new Vector3d( ); 430. currt3d.get( currTrans ); 431. printTuple( currTrans, id); 432. } // end of printTG()

433. private void printTuple(Tuple3d t, String id) 434. // used to print Vector3d, Point3d objects 435. { 436. System.out.println(id + " x: " + df.format(t.x) +

a. ", " + id + " y: " + df.format(t.y) +

b. ", " + id + " z: " + df.format(t.z));

437. } // end of printTuple()

438. } // end of PropManager class

Page 31: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

30

Anexo 5.

Modelos

Figura 6. Cono.

Figura 7. Toroide.

Figura 8. Icosfera.

Figura 9. Cilindro.

Figura 10. Cubo.

Page 32: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

31

Anexo 6.

Marcadores

Figura A). pattKanji.

Figura C). pattHiro.

Figura B). Marker3.

Figura D). Marker 5.

Page 33: 0. Índice. - 148.206.53.84148.206.53.84/tesiuami/UAMI16757.pdf · de un brazo robótico, el cual funcione mediante un entorno de Realidad Aumentada, agregando visualmente a las imágenes

32

Anexo 7.

Matriz

Figura 11. Matriz de estimulación.