En la anterior entrada podréis ver la idea, que era obtener información de los sensores y pasarla a la capa de código nativo a través de JNI para aprovechar la velocidad del código nativo y emplear los beneficios de la librería OpenCV.
Por el momento para simplificar el problema, vamos a empezar por algo sencillo sin mucha complicación y asumiendo dos premisas:
- Partimos de que el móvil esta en una posición de landscape y que el usuario sí puede moverse, pero digamos que la rotación no está soportada (más adelante os explicaré porque pongo tantas pegas).
- El código está pensado para un Nexus 4 donde he estimado que el ángulo de la amplitud de la cámara es de unos 70º.
Una de las cosas que más me gusta cuando programo es separar correctamente la lógica de las diferentes partes porque sobretodo en Android puede llegarse a mezclarse mucho.
Si nos damos cuenta la programación en muchos de los flujos de Android recuerda mucho a la programación asíncrona de lenguajes Javascript, donde continuamente estás empleando callbacks. Uno de los problemas más habituales es acabar con una actividad con demasiado código que arranca sensores, tiene llamadas asíncronas, etc. Por eso para este ejemplo tenemos dos ejemplos bien diferenciados:
- MainActivity: La actividad principal, que es la que arrancará la aplicación, configurará OpenCV para su funcionamiento y recibirá los callback de los sensores con la orientación del móvil ya procesada que enviará a través de JNI.
- CompassSensor: Singleton poblado con el contexto padre de toda la aplicación que se encargará de preprocesar los eventos del acelerómetro y la brújula, y los notifica a las actividades subscritas (en este caso MainActivity) para que los procesen..
En la parte nativa pura que es invocada desde la actividad que se encarga de pintar un círculo donde está nuestro punto objetivo (para el ejemplo hemos elegido la coordenada 100º) además de la coordenada actual. Se encuentra en el fichero jni_part.cpp:
Simplemente sabiendo el tamaño horizontal de la pantalla (width), el ángulo de visión y la orientación actual, podemos estimar dónde debemos centrar el círculo con el punto a seguir (el marker).
A continuación podéis ver un vídeo de demostración (si lo hacéis en casa, agitad un poco la brújula para mejores lecturas :P ):
Como vemos, OpenCV nos aísla de una manera muy eficiente a la hora de poder pintar y gestionar los frames sin preocuparnos de otros parámetros de la cámara. Como es obvio el ejemplo debe ser extendido y mejorado, a continuación describimos los problemas que quedan por resolver:
- Ángulo de la cámara: Por ahora este ejemplo sé que se ve bien en mi Nexus 4, pero no sería válido para todos los móviles puesto que es posible que varíe el ángulo que soporta cada cámara del móvil, puesto que irá muy ligado a la focal de la cámara sin zoom y el tamaño del sensor. Antaño se incorporaba en el método getHorizontalViewAngle() del API de la cámara esta información pero al parecer no es muy fiable dependiendo del fabricante (actualmente está deprecada).
- En todo el ejemplo hemos partido con que la persona que maneja el móvil no cambia la orientación del dispositivo, no cambia la rotación. Para tener en cuenta todas estas variables, habría que calcular la orientación basándose en el pitch y en el roll (espero hacerlo para la próxima entrada), lo que nos proporcionaría más juego y además mejoraría sustancialmente nuestras posibilidades de realidad aumentada. (Los más impacientes pueden consultar este hilo.este otro y por último este hilo.

No hay comentarios:
Publicar un comentario