Advertisement
  1. Code
  2. Android SDK

Cómo Usar Servicios de Aprendizaje Automático de Google Cloud para Android

Scroll to top
Read Time: 12 min

() translation by (you can also view the original English article)

Las noticias estos días están llenas de palabras de moda tales como automatización, inteligencia artificial y aprendizaje automático. Eso es probablemente por lo que más y más usuarios de teléfonos inteligentes están comenzando a buscar aplicaciones más inteligentes. Como desarrollador regular de aplicaciones Android, sin embargo, probablemente careces de los recursos necesarios para crear tales aplicaciones desde cero.

Afortunadamente, Google recientemente lanzó una plataforma de Aprendizaje Automático en la Nube, que ofrece redes neuronales que han sido pre-entrenadas para realizar una variedad de tareas. La mayoría de sus modelos no solo son altamente precisos, sino también están en constante mejora. ¿Y adivina qué? ¡Puedes usarlos simplemente haciendo unas cuantas llamadas API REST!

En este tutorial te presentará la plataforma de Aprendizaje Automático en la Nube y te mostraré cómo usarla para crear una aplicación Android inteligente que puede reconocer objetos del mundo real y nombrarlos en múltiples lenguajes.

Prerrequisitos

Para sacar lo mejor de este tutorial, todo lo que necesitas es:

1. Adquiriendo una Llave API

Para poder usar los servicios de aprendizaje automático de Google en tu aplicación Android, necesitas una llave API. Puedes obtener una creando un nuevo proyecto en la consola de Plataforma Google Cloud.

Comienza iniciando sesión en la consola y presionando el botón Crear Nuevo Proyecto. En el diálogo que emerge, dale un nombre significativo al proyecto.

Create new projectCreate new projectCreate new project

Una vez que el proyecto ha sido creado, ve a Administrador API > Tablero y presiona el botón Habilitar API.

En la siguiente pantalla, bajo el encabezado Aprendizaje Automático Google Cloud, podrás ver todas las diferentes APIs de aprendizaje automático disponibles para ti. En este tutorial, estaremos usando solo las APIs Visión y Traducción

Machine learning libraryMachine learning libraryMachine learning library

Para habilitar la API Visión, da clic en su enlace y presiona el botón Habilitar.

Enable Vision APIEnable Vision APIEnable Vision API

De manera similar, para habilitar la API Traducción, da clic sobre su enlace y presiona el botón Habilitar.

Solo necesitarás una llave para usar ambas APIs. Para obtenerla, ve a la pestaña de Credenciales, presiona el botón Crear credenciales, y selecciona llave API.

Select API keySelect API keySelect API key

Ahora deberías ver una ventana emergente conteniendo tu llave API secreta.

2. Creando un Nuevo Proyecto Android

Inicia Android Studio y crea un nuevo proyecto con una actividad vacía. Te sugiero que elijas al menos API nivel 19 para el SDK mínimo soportado.

Aunque no tienes que hacerlo, siempre es una buena idea usar una librería robusta de trabajo en red para comunicar con la plataforma de Aprendizaje Automático Google Cloud. En este tutorial, estaremos usando una de esas librerías llamada Fuel. Agrégala como una dependencia compile en el archivo build.gradle del módulo de app:

1
compile 'com.github.kittinunf.fuel:fuel-android:1.5.0'

Presiona Sync Now para actualizar tu proyecto.

Después, nuestra aplicación necesitará el permiso INTERNET para comunicarse con los servidores de Google. Así pues, agrega la siguiente línea dentro del archivo manifest del proyecto:

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

Por último, agrega tu llave API al archivo values/strings.xml:

1
<string name="mykey">ABCDEF12345-abcdef12345-123</string>

3. Usando la API Visión

La API Visión te ayuda a crear aplicaciones que pueden ver y hacer sentido del entorno del usuario. La detección de rostros, detección de emociones, reconocimiento de caracter óptico, y comentario de imagen son algunas de sus muchas características. Por ahora, nos estaremos concentrando solo en la poderosa característica de comentario de imagen, también llamada detección de etiqueta---la cual, en mi opinión, es muy útil.

Como podrías esperar, la API espera una imagen como una de sus entradas. Así pues, creemos una pantalla en donde el usuario puede capturar imágenes usando la cámara del dispositivo.

Paso 1. Crea un Diseño

El diseño de nuestra pantalla debería tener widget Button que el usuario puede presionar para tomar una fotografía, un widget ImageView para mostrar la imagen, y un widget TextView para mostrar las etiquetas, o comentarios, generados por la API. De manera acorde, agrega el siguiente código al archivo XML de diseño de tu actividad:

1
<Button android:text="Take a picture"
2
    android:layout_width="match_parent"
3
    android:layout_height="wrap_content"
4
    android:id="@+id/takePictureButton"
5
    android:onClick="takePicture"/>
6
7
<ImageView
8
    android:layout_width="wrap_content"
9
    android:layout_height="wrap_content"
10
    android:layout_below="@id/takePictureButton"
11
    android:id="@+id/previewImage"
12
    android:layout_centerHorizontal="true"/>
13
14
<TextView
15
    android:layout_width="wrap_content"
16
    android:layout_height="wrap_content"
17
    android:id="@+id/resultsText"
18
    android:layout_below="@id/previewImage"/>

Nota que hemos asociado un manejador onClick con el botón. Lo definiremos en el siguiente paso.

Paso 2: Crea un Intent

Creando un nuevo intent con la acción ACTION_IMAGE_CAPTURE y pasándolo al método startActivityForResult(), puedes pedir a la aplicación de cámara por defecto del dispositivo del usuario tomar fotografías y pasarlas a tu aplicación. Así pues, agrega el siguiente código a tu clase Activity:

1
public final static int MY_REQUEST_CODE = 1;
2
3
public void takePicture(View view) {
4
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
5
    startActivityForResult(intent, MY_REQUEST_CODE);
6
}

Para poder recibir las imágenes capturadas por la aplicación de cámara por defecto, debes anular el método onActivityResult() de tu clase Activity. Dentro del método, tendrás acceso a un objeto Bundle conteniendo toda la información de la imagen. Puedes generar la información de la imagen simplemente convirtiéndola a un Bitmap y pasándola al widget ImageView.

1
@Override
2
protected void onActivityResult(int requestCode, int resultCode,
3
                                Intent data) {
4
    if(requestCode == MY_REQUEST_CODE && resultCode == RESULT_OK) {
5
6
        // Convert image data to bitmap

7
        Bitmap picture = (Bitmap)data.getExtras().get("data");
8
9
        // Set the bitmap as the source of the ImageView

10
        ((ImageView)findViewById(R.id.previewImage))
11
                                .setImageBitmap(picture);
12
13
        // More code goes here

14
    }
15
}

Si ejecutas la aplicación ahora y tomas una foto, verás que el tamaño de la imagen es bastante pequeño. Eso está bien, sin embargo---la API Cloud Vision es muy precisa incluso con miniaturas de imagen.

Paso 3: Codifica la Imagen

La API Visión no puede usar objetos Bitmap directamente. En su lugar, espera una cadena de texto codificada en Base64 de información comprimida de imagen.

Para comprimir la información de la imagen, puedes usar el método compress() de la clase Bitmap. Como sus argumentos, el método espera el formato de compresión a usar, la calidad de salida deseada, y un objeto ByteArrayOutputStream. El siguiente código comprime el bitmap usando el formato JPEG y también asegura que la calidad de la imagen resultante es lo suficientemente alta:

1
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
2
picture.compress(Bitmap.CompressFormat.JPEG, 90, byteStream);

Ahora puedes generar la cadena Base64 usando el método encodeToString() de la clase Base64().

1
String base64Data = Base64.encodeToString(byteStream.toByteArray(), 
2
                                          Base64.URL_SAFE);

Paso 4: Procesa la Imagen 

Después de todo ese arduo trabajo, tienes todo lo que necesitas para interactuar con la API Visión. Comienza creando una cadena que contenga la URL de la API y tu llave API:

1
String requestURL = 
2
        "https://vision.googleapis.com/v1/images:annotate?key=" +
3
         getResources().getString(R.string.mykey);

Para enviar información a la API, debes crear una petición HTTP POST. El cuerpo de la petición debe ser un documento JSON conteniendo la información de la imagen codificada en Base64. Para detección de etiqueta, el documento también debe tener un arreglo features conteniendo el valor LABEL_DETECTION. Aquí está el formato del documento JSON.

1
{"requests": [{
2
      "image": {
3
        "content": <Base64-encoded image data>
4
      },
5
      "features": [{
6
          "type": "LABEL_DETECTION"
7
      }]
8
}]}

Aunque es posible codificar a mano el documento JSON, crearlo de manera programática es menos propenso al error. El siguiente código te muestra cómo hacerlo usando las clases JSONObject y JSONArray:

1
// Create an array containing

2
// the LABEL_DETECTION feature

3
JSONArray features = new JSONArray();
4
JSONObject feature = new JSONObject();
5
feature.put("type", "LABEL_DETECTION");
6
features.put(feature);
7
8
// Create an object containing

9
// the Base64-encoded image data

10
JSONObject imageContent = new JSONObject();
11
imageContent.put("content", base64Data);
12
13
// Put the array and object into a single request

14
// and then put the request into an array of requests

15
JSONArray requests = new JSONArray();
16
JSONObject request = new JSONObject();
17
request.put("image", imageContent);
18
request.put("features", features);
19
requests.put(request);
20
JSONObject postData = new JSONObject();
21
postData.put("requests", requests);
22
23
// Convert the JSON into a

24
// string

25
String body = postData.toString();

En este punto, podemos usar el método post() de la clase Fuel para hacer la petición HTTP POST. Como su único argumento, el método espera la URL de la API. También debes incluir los encabezados content-length y content-type en la petición. Para hacerlo, usa el método header(). De manera similar, para poder agregar el documento JSON al cuerpo de la petición POST, usa el método post().

Por último, llamando al método responseString() y pasando una nueva instancia de la clase Handler a este, puedes obtener de manera asíncrona la respuesta de la petición como una cadena. De manera acorde, agrega el siguiente código:

1
Fuel.post(requestURL)
2
    .header(
3
        new Pair<String, Object>("content-length", body.length()),
4
        new Pair<String, Object>("content-type", "application/json")
5
        )
6
    .body(body.getBytes())
7
    .responseString(new Handler<String>() {
8
        @Override
9
        public void success(@NotNull Request request,
10
                            @NotNull Response response,
11
                            String data) {
12
            // More code goes here

13
        }
14
15
        @Override
16
        public void failure(@NotNull Request request,
17
                            @NotNull Response response,
18
                            @NotNull FuelError fuelError) {}
19
    });

Cuando usas la característica de detección de etiqueta, la API Visión devuelve un documento JSON conteniendo etiquetas. Junto con cada etiqueta, puedes también obtener una puntuación especificando qué tan certera es la etiqueta. El documento luce como esto:

1
{"responses":[{
2
  "labelAnnotations": [
3
    {
4
      "mid": "/m/id1",
5
      "description": "label1",
6
      "score": 0.91
7
    },
8
    {
9
      "mid": "/m/id2",
10
      "description": "label2",
11
      "score": 0.90
12
    },
13
  ...
14
}]}

Por ahora, solo ciclemos a través de todos los objetos en el arreglo labelAnnotations y agrega el valor de cada llave description al widget TextView de nuestro diseño. Aquí está cómo puedes hacer eso dentro del método success() de la clase Handler:

1
// Access the labelAnnotations arrays

2
JSONArray labels = new JSONObject(data)
3
                    .getJSONArray("responses")
4
                    .getJSONObject(0)
5
                    .getJSONArray("labelAnnotations");
6
7
String results = "";
8
9
// Loop through the array and extract the

10
// description key for each item

11
for(int i=0;i<labels.length();i++) {
12
    results = results + 
13
              labels.getJSONObject(i).getString("description") +
14
              "\n";
15
}
16
17
// Display the annotations inside the TextView

18
((TextView)findViewById(R.id.resultsText)).setText(results);

Ahora puedes ejecuta la aplicación, tomar una foto de cualquier objeto cercano, y ver las etiquetas que la API Visión genera para este.

Labels generated for a laptopLabels generated for a laptopLabels generated for a laptop

4. Usando la API Traducción

La API de Traducción en la Nube, como sugiere su nombre, puede traducir texto desde y hacia más de 100 lenguajes. Al usarla de manera efectiva, puedes crear aplicaciones inteligentes que puedan comunicarse con tus usuarios en sus propios lenguajes.

En el paso anterior, viste que las etiquetas que nuestra aplicación genera están en inglés. Agreguemos ahora un botón para traducir esas etiquetas a Alemán.

Paso 1: Actualiza el Diseño

Agrega un widget Button hacia el final del diseño de tu Activity usando el siguiente código:

1
<Button
2
    android:layout_width="match_parent"
3
    android:layout_height="wrap_content"
4
    android:layout_below="@+id/resultsText"
5
    android:text="in German"
6
    android:onClick="translateToGerman"/>

Nota que este botón también tiene un manejador de evento onClick que debe ser definido en tu clase Activity.

Paso 2: Traduce las Etiquetas

Usando la API de Traducción es mucho más sencillo que usar la API Visión, primariamente porque no necesitas crear un documento JSON para definir tu petición. en su lugar, puedes simplemente pasarle parámetros en una cadena de consulta.

Crea el método translateToGerman() y, dentro de este, crea una cadena conteniendo la URL de la API de Traducción.

1
public void translateToGerman(View view) {
2
    String requestURL = 
3
        "https://translation.googleapis.com/language/translate/v2";
4
5
    // More code goes here

6
}

Para agregar campos a la cadena de consulta de la URL de arriba, podemos usar una List de objetos Pair. Los siguientes campos son importantes:

  • key, especificando tu llave API secreta
  • source, especificando el lenguaje desde el que quieres traducir 
  • target, especificando el lenguaje al que quieres traducir
  • q, especificando el texto que quieres traducir

El siguiente código te muestra cómo configurar la API para traducir de Inglés a Alemán:

1
List<Pair<String, String>> params = new ArrayList<>();
2
// Add API key

3
params.add(new Pair<String, String>("key", 
4
                        getResources().getString(R.string.mykey)));
5
6
// Set source and target languages

7
params.add(new Pair<String, String>("source", "en"));
8
params.add(new Pair<String, String>("target", "de"));

Debido a que la cadena de consulta puede contener múltiples campos q, estaremos agregando uno por cada etiqueta que esté presente dentro del widget TextView dentro de nuestro diseño. Aquí está cómo:

1
String[] queries = ((TextView)findViewById(R.id.resultsText))
2
                    .getText().toString().split("\n");
3
4
for(String query:queries) {
5
    params.add(new Pair<String, String>("q", query));
6
}

Finalmente, puedes llamar al método get() de la clase Fuel para hacer una petición HTTP GET a la API de traducción. Esta vez también, puedes usar el método responseString() para obtener la respuesta de manera asíncrona como una cadena de texto.

1
Fuel.get(requestURL, params).responseString(new Handler<String>() {
2
    @Override
3
    public void success(@NotNull Request request, 
4
                        @NotNull Response response,
5
                        String data) {
6
        // More code here

7
    }
8
9
    @Override
10
    public void failure(@NotNull Request request, 
11
                        @NotNull Response response, 
12
                        @NotNull FuelError fuelError) { }
13
});

La respuesta de la API de Traducción es un documento JSON conteniendo un arreglo de traducciones. Tiene el siguiente formato:

1
{ "data": { "translations": [
2
  {
3
    "translatedText": "...."
4
  },
5
  {
6
    "translatedText": "...."
7
  },
8
  ...
9
] } }

Por ahora, dentro del método success() de la clase Handler, simplemente ciclemos a través del arreglo translations del documento JSON de arriba, y actualicemos los contenidos del widget TextView usando los valores asociados con las llaves translatedText.

1
// Access the translations array

2
JSONArray translations = new JSONObject(data)
3
                        .getJSONObject("data")
4
                        .getJSONArray("translations");
5
6
// Loop through the array and extract the translatedText

7
// key for each item

8
String result = "";
9
for(int i=0;i<translations.length();i++) {
10
    result += translations.getJSONObject(i)
11
                .getString("translatedText") + "\n";
12
}
13
14
// Update the contents of the TextView widget

15
((TextView)findViewById(R.id.resultsText)).setText(result);

Si ejecutas la aplicación ahora, generas etiquetas para una imagen, y presionas el segundo botón, deberías poder ver las etiquetas en Alemán.

Labels in GermanLabels in GermanLabels in German

Conclusión

En este tutorial, aprendiste cómo usar las APIs Cloud Vision y Cloud Translation, que son parte de la plataforma de Aprendizaje Automático Google Cloud, en una aplicación Android. Hay muchas más de estas APIs ofrecidas por la plataforma. Puedes aprender más acerca de ellas refiriéndote a la documentación oficial.

Mientras estás aquí, ¡revisa algunos de nuestros otros tutoriales sobre cómo usar servicios de aprendizaje automático y en la nube en tus aplicaciones Android!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.