Iniciando con Wikitude para Android: instalación de la SDK y primeros pasos en el reconocimiento de imágenes

23-07-2018 - Andrés Cruz

In english

Ver ejemplo en github

La realidad aumentada en Wikitude, los Puntos de Interés, el reconocimiento de imágenes y mucho más es un tema ya tratado en anteriores entradas que hablamos sobre Wikitude:

Iniciando con Wikitude para Android: instalación de la SDK y primeros pasos en el reconocimiento de imágenes

Continuar leyendo

Primeros pasos con Wikitude en Android (parte 1)

Continuar leyendo

Creando un Punto de Interés con Realidad Aumentada en Wikitude Parte 2

Continuar leyendo

Creando un Punto de Interés con Realidad Aumentada en Wikitude Parte 1

Continuar leyendo

¿Cómo reconocer múltiples Objetivos (Targets) con el Tracker en Wikitude?

Continuar leyendo

Puntos de Interés (POI) con Realidad Aumentada en Wikitude

Continuar leyendo

Target Collection y el ARchitect World en la nube con Wikitude

Continuar leyendo

Desarrollando aplicaciones de Realidad Aumentada con Wikitude (parte 3.2)

Continuar leyendo

Desarrollando aplicaciones de Realidad Aumentada con Wikitude (parte 3)

Continuar leyendo

Las medidas SDUs en Wikitude

Continuar leyendo 

Y la entrada anterior a esta; en esta entrada veremos cómo crear una aplicación que emplee la SDK de Wikitude naiva para Android y emplee el reconocimiento de imágenes para (valga la redundancia) reconocer una imagen y mostrar un enmarque a su alrededor.

En aquellos tiempos cuando existía el famoso Eclipse con el plugin ADT desde ese tiempo han cambiado varias cosas, muchas versiones de Android han pasado, varias de la SDK de Wikitude hasta estar en la versión 8, que es la actual, e inclusive han extendido su SDK hasta crear una nativa para Android.

La SDK nativa y la SDK web/JavaScript

Recordemos que para versiones anteriores solo estaba disponible una especie de SDK híbrida en donde parte de la SDK era nativa (el uso de la cámara y configuración inicial), pero el fuerte del reconocimiento de imágenes, uso de los POIs o Puntos de Interés, interacción con el usuario, conectarse a otras API para traer o enviar datos y más, se realizaba mediante JavaScript; que a mi humilde opinión me parece excelente este esquema ya que facilita mucho el proceso de creación de las app, podemos trabajar en gran parte con librerías y demás funcionalidades webs que desde Android nos harían pasar más trabajo por cómo está elaborado este.

Sin embargo el talón de aquiles de esta funcionalidad es que las interfaces al ser webs no están a la altura de un desarrollo nativo en Android; para ello Wikitude creó una versión nativa para Android paralela a la de JavaScript que podemos usar según nuestras necesidades:

wikitude javascript y nativa android

Las SDK de Wikitude para Android y otras más las puedes descargar desde el siguiente enlace oficial:

Wikitude SDK para Android

Claro, desarrollar con la SDK nativa puede ser más complejo que con la SDK para web pero todo depende de las ventajas que veamos entre una y otra al momento de realizar un proyecto.

En esta entrada, nos enfocaremos en dar los primeros pasos con el desarrollo de una sencilla aplicación para el reconocimiento de imágenes, para ello haremos uso de los ejemplos oficiales casi en su totalidad, pero la idea de esta entrada es narrar como yo desarrollé y probé estos ejemplos de una manera más limpia, explicar como funciona y cómo nos podemos ayudar con la documentación.

Instalación de la SDK nativa

Lo primeros que debemos hacer es descargar la SDK natíva de Wikitude para Android; para ello puedes descargarlo desde la sección de descargas:

Wikitude SDK para Android

Probablemente debas registrarte, aceptar unas condiciones etc; una vez descargada la misma, las descomprimes y tendremos en la ruta:

WikitudeSDK_NativeAPI_Android_8-X-X_XXXX-XX-XX_XX-XX-XX\Library
aar librería de wikitude

Esta librería o SDK de Wikitude que instalaremos en nuestro Android Studio; el proceso consiste en copiar la librería en la carpeta libs de Android:

árbol de proyecto android studio

Y luego seguir los pasos que narran en la documentación oficial:

Setup Guide Android

Básicamente consiste en agregar las dependencias en nuestro Android Gradle:

android {
    ...
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation (name: 'wikitude-native-sdk', ext:'aar')
    implementation "com.google.ar:core:1.1.0"
    ...
}

repositories {
    flatDir{
        dirs 'libs'
    }
}

Y en solicitar los permisos en nuestro Android Manifest:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />

<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<uses-feature android:name="android.hardware.camera" android:required="true" />

 

Colocar estos atributos en la actividad que emplea la realidad aumentada, que en nuestro ejemplo es nuestro MainActivity:

android:configChanges="orientation|keyboardHidden|screenSize"

Quedando nuestra MainActivity la cual es la que va a mostrar la realidad aumentada mediante la cámara y la pantalla del dispositivo de la siguiente forma:

<activity
   android:name=".MainActivity"
   android:configChanges="orientation|keyboardHidden|screenSize">

Una vez hecho esto, nuestro proyecto debería compilar sin problemas, aunque aún no hemos desarrollado nada.

Iniciando con el Reconocimiento de Imágenes de WIkitude

Como mencionamos antes, vamos a hacer uso de los ejemplos que ofrece Wikitude, y que vienen en el zip que descargamos y descomprimimos antes:

WikitudeSDK_NativeAPI_Android_8-X-X_XXXX-XX-XX_XX-XX-XX\Library\app\src\main\java\com\wikitude\samples\tracking\image\SimpleImageTrackingActivity.java

En la documentación oficial nos podemos guiar por este links que nos van explicando un paso a paso hasta cierto punto:

Simple Image Tracking Android

Nos narra unos pasos que consisten en implementar algunas clases propias de la SDK de Wikitude:

public class MainActivity extends Activity implements ImageTrackerListener, ExternalRendering {...}

Nos indica que en nuestro OnCreate el cual es el método inicial en nuestro ciclo de vida de una aplicación Android realizamos las configuraciones de la aplicación, creando el objeto WikitudeSDK con la cual realizamos las configuraciones para indicar la licencia que descargamos desde el punto anterior, la cámara que vamos ha usar, si la delantera o de la parte posterior, la resolución, y luego creamos una instancia de la SDK de Wikitude con los parámetros configurados:

wikitudeSDK.onCreate(getApplicationContext(), this, startupConfiguration);

Creando el TargetCollection

Paso siguiente es crear el TargetCollection que ya hemos hablado de esto antes en una anterior entrada:

Target Collection y el ARchitect World en la nube con Wikitude

Empleando la API nativa de Wikitude, para referenciar el TargetCollection hacemos:

targetCollectionResource = wikitudeSDK.getTrackerManager().createTargetCollectionResource("file:///android_asset/magazine.wtc");

La ruta android_asset hace referencia al directorio assets de nuestro proyecto que podemos crear desde Android Studio:

arbol proyecto assets carpeta

También agregamos o mejor dicho sobreescribimos algunos métodos del propios de la clase que estamos implementando:

@Override
public void onTargetsLoaded(ImageTracker tracker) {
    Log.v(TAG, "Image tracker loaded");
}

@Override
public void onErrorLoadingTargets(ImageTracker tracker, WikitudeError error) {
    Log.v(TAG, "Unable to load image tracker. Reason: " + error.getMessage());
}

@Override
public void onImageRecognized(ImageTracker tracker, final ImageTarget target) {
    Log.v(TAG, "Recognized target " + target.getName());

    StrokedRectangle strokedRectangle = new StrokedRectangle(StrokedRectangle.Type.STANDARD);
    glRenderer.setRenderablesForKey(target.getName() + target.getUniqueId(), strokedRectangle, NULL);
}

@Override
public void onImageTracked(ImageTracker tracker, final ImageTarget target) {
    StrokedRectangle strokedRectangle = (StrokedRectangle)glRenderer.getRenderableForKey(target.getName() + target.getUniqueId());

    if (strokedRectangle != NULL) {
        strokedRectangle.projectionMatrix = target.getProjectionMatrix();
        strokedRectangle.viewMatrix = target.getViewMatrix();

        strokedRectangle.setXScale(target.getTargetScale().getX());
        strokedRectangle.setYScale(target.getTargetScale().getY());
    }
}

@Override
public void onImageLost(ImageTracker tracker, final ImageTarget target) {
    Log.v(TAG, "Lost target " + target.getName());
    glRenderer.removeRenderablesForKey(target.getName() + target.getUniqueId());
}

Y el siguiente método que es muy importante el permite de hacer de espejo el contenido de la cámara en la pantalla; en otras palabras: renderiza el contenido de la cámara en la pantalla y habilita la Realidad Aumentada:

@Override
public void onRenderExtensionCreated(final RenderExtension renderExtension) {
    glRenderer = new GLRenderer(renderExtension);
    view = new CustomSurfaceView(getApplicationContext(), glRenderer);
    driver = new Driver(view, 30);
    setContentView(view);
}

Aquí como vemos la cosa se complica un poco ya que hacemos uso de otras clases y métodos que de repente aparecieron en la documentación; lo más importante aquí es tener presente los métodos autogenerados por la API de Wikitude que prácticamente se auto explican con su nombre pero aun así vamos a definirlos un poco a continuación:

Ya con esta ayuda, lo mejor que podemos hacer es ir viendo método por método y analizar qué es lo que está haciendo.

Método onCreate

En el método onCreate lo siguiente que hacemos es solicitar permiso para emplear la cámara, ya esto es algo propio de Android desde la versión 6, si la solicitud es rechazada, pues no hay nada que hacer, ya que no podrá funcionar la realidad aumentada de Wikitude y menos reconocer imágenes.

Paso siguiente esta líneas de código que son opcionales:

dropDownAlert = new DropDownAlert(this);
dropDownAlert.setText("Scan Target #1 (surfer):");
dropDownAlert.addImages("surfer.png");
dropDownAlert.setTextWeight(0.5f);
dropDownAlert.show();

Lo que haces es pintar un rectángulo en la parte superior de la pantalla:

panel ra

En los métodos onResume, onPause y onDestroy lo que hacemos es controlar el ciclo de vida de la aplicación y de algunos componentes que son fundamentales para que trabaje y no nos de algún error inesperado cuando la aplicación pase de un estado a otro y pueda destruirse correctamente.

Tipos de renderizado: Externo e Interno

Tenemos dos tipos de renderizado, el interno y el externo y esto es lo que pinta habilita la cámara en la pantalla (fíjese que ahora no empleamos un layout especial que funcionaba como espejo entre la cámara y la pantalla como se hace en la versión web).

El método onRenderExtensionCreated es definido con el renderizado externo ya que estamos pasando nuestro parámetro OpenGL a 30 frames por segundo.

Y en este punto es donde ocurre la magia, en donde Wikitude muestra o espeja el contenido de la cámara en la pantalla del dispositivo y habilita toda la SDK de Wikitude a nuestra disposición (Reconocimiento de imágenes, Puntos de interés, y la realidad aumentada en general).

Clase GLRenderer

En general estas clases no las tenemos que analizar mucho, con saber que es la que nos construye la superficie de vista o SurfaceView nos es suficiente para trabajar con ella; la misma se encarga de construir la vista según el tamaño de la pantalla.

GLRenderer implementa un par de clases, la primera de ellas es GLSurfaceView.Renderer que emplea la librería OpenGL que permite realizar gráficos e interfaces en 2D y 3D; ya con esto puedes suponer que estos graficos en Wikitude se refieren al lente (la pantalla) que refleja el contenido enviado por la cámara del dispositivo.

¿Cómo se comunica Wikitude con esta interfaz GLSurfaceView.Renderer

Pues para eso Wikitude cuenta con su propia interfaz llamada RenderExtension la cual es inicializada en el método GLRenderer como parámetro generado en el método sobrescrito en la actividad principal llamado onRenderExtensionCreated; asi de facil, aunque suene un poco enredado; esta interfaz RenderExtension fue creada específicamente para el renderizado de externo de la SDK de Wikitude.

El método useSeparatedRenderAndLogicUpdates trabaja en conjunto con el método onDrawFrame que permite actualizar el renderizado de la aplicación.

Los métodos onSurfaceCreated, onSurfaceChanged y onDrawFrame son métodos provistos por la misma interfaz GLRenderer que se encargan de realizar los cambios en la pantalla y de dibujar cada frame, de estar realizando cambios cada vez que exista una actualización, etc; con esto ves que es importante realizar las llamadas correspondientes en los onPause y onDestroy de la actividad.

La clase GLES20 junto con los métodos que invoca simplemente se encarga de limpiar buffer; ya esto es algo bastante interno de OpenGL que de nuevo no es necesario trabajar con esto para explotar las funcionalidades básicas del core de la SDK de Wikitude.

Lo demás que vemos es simplemente como la SDK de Wikitude se comunica con los métodos provistos en OpenGL y trabajar correctamente; sin nada de esto No será posible que Wikitude renderice los frames de la cámara en la pantalla en otras palabras, nos quedaría una pantalla en blanco, negro o simplemente la app no funciona; la misma define mediante CameraManager.FovChangedListener el método onFovChanged que vemos al final del código.

La interfaz CameraManager, es provista por Wikitude y permite controlar la cámara que es la entrada de la realidad aumentada que hace posible que todo lo demás trabaje correctamente

Aquí tienes algunos enlaces de interés con la documentación oficial:

Clase CustomSurfaceView: construye la vista a embeber en la actividad

 

La otra clase que empleamos en el método onRenderExtensionCreated es la de CustomSurfaceView que le pasamos una instancia de la clase glRenderer que explicamos en la sección anterior; esta clase CustomSurfaceView extiende de la clase GLSurfaceView que provee una superficie para mostrar un reenderizado OpenGl (que es el que generamos en el punto anterior), es decir, en una clase la de glRenderer genera,ps el renderizado que queremos mostrar mediante OpenGL y WIkitude y en esta clase simplemente generamos la superficie con este contenido y lo embebemos en la actividad como si de una vista se tratase:

customSurfaceView = new CustomSurfaceView(getApplicationContext(), glRenderer);
***
setContentView(customSurfaceView);

Esta clase en resumidas cuentas lo que haces es crear un contexto para renderizar y sobre esta una superficie para dibujar mediante el "EGL rendering context"; ya aquí están dos grandes factores en juego que hacen todo por nosotros OpenGL-Android y Wikitude.

Aquí en estos últimos puntos vemos el talón de aquiles de la API nativa de Wikitude para Android, y es que algunos componentes son más complejos como estos que vimos, cosa con la cual no tenemos que lidiar en la API web o JavaScript de Wikitude para Android.

 

Clase StrokedRectangle: Pintar enmarque del target reconocido

 

Esta clase es invocado desde el MainActivity de nuestra actividad mediante el método onImageTracked que obtiene las dimensiones y posición del objeto reconocido y en el método onImageRecognize que dibuja el rectángulo correspondiente sobre la imagen reconocida (además de que este método nos permite obtener el nombre del target reconocido mediante target.getName()).

Esta clase dibuja el rectángulo en la función onDrawFrame() de dicha clase; todo esto es empleando la API de OpenGL que no es el punto de interés de esta entrada.

Puedes consultar el código completo en los links de descarga ubicados al inicio y final del este tutorial de realidad aumentada con Wikitude native SDK y Android; recuerda copiar el directorio rendering dentro del paquete de tu aplicación con el contenido del mismo:

 rendering external archivos

Finalmente, al ejecutar la aplicación y posicionar la cámara sobre la siguiente foto; vemos que la SDK de Wikitude reconoce dicha imagen y coloca un rectángulo alrededor de la misma:

reconocimiento de imágenes Wikitude

Ver ejemplo en github


Andrés Cruz
Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz en Udemy

Acepto recibir anuncios de interes sobre este Blog.

!Cursos a!

10$

En Udemy

Quedan 4 días!

Ver los cursos
¡Hazte afiliado en Gumroad!

!Cursos desde!

4$

En Academia

Ver los cursos

!Libros desde!

1$

Ver los libros
!Web Alojada en Hostinger!