Microsoft, Xamarin, Xamarin.Forms

Microsoft Cognitive Services [Emotions.API && Xamarin.Forms] DEMO


EmotionAPI.PNG

Emotion API:
Reconoce y extrae emociones de una persona a partir de una fotografia o video.

¿Como funciona Emotion API?

El Emotion API toma como entrada uno o varios rostros (en una imagen o video) para analizar la expresion facial y regresa el grado de confianza (score) de un conjunto de emociones para cada rostro, asi como un cuadro delimitador del rostro en conjunto con el Face API.

¿Cuantas emociones podemos detectar?

Se pueden detectar 8, las cuales son:

Ira | Desperecio | Disgusto | Temor | Felicidad | Neutralidad | Tristeza | Sorpresa

EmotionAPI2.PNG

DEMO

Antes de tirar código debemos de contar con una cuenta de Microsoft Cognitive Services, cabe destacar que existen planes gratuitos que pueden utilizar para probar el servicio.

Para esto ingresemos al portal de Microsoft Cognitive Services (http://microsoft.com/cognitive).

Regístrate dando clic en My account.

ms-cognitive-services-my-account

Acepta la solicitud de permisos:

permisos-ms-cognitive-services

Una ves en el portal podremos ver todos los “productos” que podemos utilizar.
Lo único que debemos hacer es dar clic en el botón Request new trials para poder suscribirnos a los servicios que deseemos (todos ofrecen planes gratuitos).

ms-cognitive-services-my-account-2

Como ya suponen, para este demo utilizaremos los servicios de Emotions. Basta con darle en Show para poder copiarlas, puesto que las utilizaremos mas adelante.

ms-cognitive-services-keys-emotio-api

Ahora si, comencemos por crear un nuevo proyecto en Visual Studio de Xamarin Forms (Visual C# – Cross Platform – Blank App (Xamarin.Forms Portable)):

demo1.PNG

Una vez proporcionado el nombre y ubicación, debemos hacer clic en Aceptar para crear el proyecto. Posterior a esto nos aparecerá un cuadro de dialogo denominado “Nuevo proyecto de Windows Universal”, al cual elegiremos la opción nuevamente de Aceptar para que se creen las versiones sugeridas de nuestra aplicación en UWP.

demo2

Ahora lo que haremos sera añadir los 4 paquetes NuGet (Este paso lo tienes que repetir por cada proyecto que quieras probar). Para ello, daremos clic derecho en el nombre del proyecto (Android, iOS, UWP, Windows, Windows Phone) y seleccionar la opción Manage NuGet packages (Administrar paquetes NuGet…).

Los paquetes a agregar son:

  • Bcl.Build
  • Plugin.Media
  • ProjectOxford.Vision
  • ProjectOxford.Emotion

El pase de diapositivas requiere JavaScript.

A continuación configuraremos los plugins instalados previamente, comencemos con Android. Abramos el archivo MainActivity.cs y añadamos el siguiente espacio de nombres:


using Plugin.Permissions;

Antes del método OnCreate agreguemos el siguiente código:


public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
  PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}

Posterior a esto, demos doble clic sobre Properties, en la pestaña de Android Manifest deberemos de marcar los permisos:

READ_EXTERNAL_STORAGE y WRITE_EXTERNAL_STORAGE

demo8

Guardemos y cerremos el archivo. Ahora abramos el archivo AssemblyInfo.cs (expande Properties en el Explorador de Soluciones).

Inserta las siguientes lineas de código al final del archivo:


[assembly: UsesFeature("android.hardware.camera", Required = false)]

[assembly: UsesFeature("android.hardware.camera.autofocus", Required = false)]

Preview:

demo9

Después, en el Explorador de Soluciones agregaremos dos carpetas denominadas: Class y Pages, para esto da clic derecho en el nombre del proyecto y selecciona Agregar – Nueva carpeta.

demo3

En la primera carpeta añadiremos un archivo de tipo Clase denominado ServiceImage, para esto solo demos clic secundario sobre la misma y seleccionemos Agregar – Nuevo elemento. El código completo de la clase es:


using Plugin.Media;
using System.Threading.Tasks;
using Plugin.Media.Abstractions;

namespace Demo_MSCS_EmotionApp.Class
{
public class ServiceImage
{
public static async Task<MediaFile> TakePicture(bool useCam)
{
await CrossMedia.Current.Initialize();

if (useCam)
{
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
return null;
}
}

var file = useCam
? await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
{
Directory = "Cognitive",
Name = "SC_Test.jpg"
})
: await CrossMedia.Current.PickPhotoAsync();

return file;
}
}
}

¿Que estoy haciendo?

En esencia se expone un método que decide si la imagen se tomara de la cámara o del carrete (Galería de Imágenes) del dispositivo. Una ves obtenida esta se almacenara temporalmente para posteriormente retornar hacia la referencia.

Añade un segundo archivo Clase en la misma carpeta, a esta nombrala ServiceEmotions e inserta el código a continuación:


using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.ProjectOxford.Emotion;

namespace Demo_MSCS_EmotionApp.Class
{
public class ServiceEmotions
{
static string key = "LLAVE-EMOCIONES";
public static async Task<Dictionary<string, float>> GetEmotions(Stream stream)
 {
 EmotionServiceClient cliente = new EmotionServiceClient(key);
 var emotions = await cliente.RecognizeAsync(stream);

 if (emotions == null || emotions.Count() == 0)
 return null;

 return emotions[0].Scores.ToRankedList().ToDictionary(x => x.Key, x => x.Value);
  }
 }
}

NOTA: Reemplazar LLAVE-EMOCIONES por la llave del servicio Emotions.

¿Que estoy haciendo?

El método anterior realiza una consulta al servicio Emotions, le pasa un stream de la imagen que se desea analizar por el servicio y devuelve precisamente el resultado del análisis en forma de diccionario. Cada elemento es una emoción y brinda su puntuación correspondiente (score).

Interacción con el usuario….

Bien, es hora de añadir un Forms Xaml Page a la carpeta de Pages a la cual podremos llamar EmotionsPage.

demo3-1

A continuación se muestra el código XAML, seguido del código C# de la misma:

XAML


<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Demo_MSCS_EmotionApp.Pages.EmotionsPage">

<StackLayout Padding="0">

<Image x:Name="imgPicture" WidthRequest="150" HeightRequest="150" Aspect="AspectFit"/>
<Button x:Name="btnCam" x:Id="btnCam" Text="Usar Cámara" Clicked="btnPicture_Clicked"/>
<Button x:Name="btnGalery" x:Id="btnGalery" Text="Seleccionar de la Galería" Clicked="btnPicture_Clicked"/>
<Button x:Name="btnAnalysisEmotions" Text="Analizar Emociones" Clicked="btnAnalysisEmotions_Clicked"/>
<Label x:Name="lblResult" Text="---" />

<StackLayout x:Name="Results"/>
</StackLayout>

</ContentPage>

C#


using System;
using System.IO;
using Xamarin.Forms;
using System.Collections.Generic;
using Demo_MSCS_EmotionApp.Class;

namespace Demo_MSCS_EmotionApp.Pages
{
public partial class EmotionsPage : ContentPage
{
static Stream streamCopy;
 public EmotionsPage()
 {
 InitializeComponent();
 }
 async void btnPicture_Clicked(object sender, EventArgs e)
 {
 var useCam = ((Button)sender).Text.Contains("Cámara");
 var file = await ServiceImage.TakePicture(useCam);
 Results.Children.Clear();
 lblResult.Text = "---";

 imgPicture.Source = ImageSource.FromStream(() =&gt; {
 var stream = file.GetStream();
 streamCopy = new MemoryStream();
 stream.CopyTo(streamCopy);
 stream.Seek(0, SeekOrigin.Begin);
 file.Dispose();
 return stream;
 });
 }

 async void btnAnalysisEmotions_Clicked(object sender, EventArgs e)
 {
 if (streamCopy != null)
 {
 streamCopy.Seek(0, SeekOrigin.Begin);
 var emotions = await ServiceEmotions.GetEmotions(streamCopy);

 if (emotions != null)
 {
 lblResult.Text = "---Análisis de Emociones---";
 DrawResults(emotions);
 }
 else lblResult.Text = "---No se detectó una cara---";
 }
 else lblResult.Text = "---No has seleccionado una imagen---";
 }

 void DrawResults(Dictionary&lt;string, float&gt; emotions)
 {
 Results.Children.Clear();

 foreach (var emotion in emotions)
 {
 Label lblEmotion = new Label()
 {
 Text = emotion.Key,
 TextColor = Color.Blue,
 WidthRequest = 90
 };

 BoxView box = new BoxView()
 {
 Color = Color.Lime,
 WidthRequest = 150 * emotion.Value,
 HeightRequest = 30,
 HorizontalOptions = LayoutOptions.StartAndExpand
 };

 Label lblPercent = new Label()
 {
 Text = emotion.Value.ToString("P4"),
 TextColor = Color.Maroon
 };

 StackLayout stack = new StackLayout()
 {
 Orientation = StackOrientation.Horizontal
 };

 stack.Children.Add(lblEmotion);
 stack.Children.Add(box);
 stack.Children.Add(lblPercent);

 Results.Children.Add(stack);
 }
 }
 }
}

Toca el turno a la pagina principal con la cual el usuario interactuará, para esto agreguemos otro Forms Xaml Page en la misma carpeta (Pages) y nombremosla StartPage.

A continuación el código XAML y C#:

XAML


<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Demo_MSCS_EmotionApp.Pages.StartPage">

<StackLayout>
<Button x:Name="btnEmotions" Text="Analizar Emociones" Clicked="btnEmotions_Clicked"/>
</StackLayout>

</ContentPage>

C#


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace Demo_MSCS_EmotionApp.Pages
{
public partial class StartPage : ContentPage
{
public StartPage()
{
InitializeComponent();
}
void btnEmotions_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new EmotionsPage());
}

}
}

Después de esto, deberemos de modificar el archivo App.cs para que nuestra pagina de inicio sea la que acabamos de crear.


public App()
{
//The root page of your application
MainPage = new NavigationPage(new Pages.StartPage());
}

Ya por ultimo, compila y ejecuta tu aplicación.

El resultado (Android):

El pase de diapositivas requiere JavaScript.

Versión Windows

Ahora bien, probemos como se ve nuestra aplicación en Windows 10, para esto hagamos lo siguiente:

Selecciona el proyecto de UWP – Botón secundario – Establecer como proyecto de Inicio

Instalemos los 4 paquetes NuGet al igual como lo realizamos en el proyecto Android.

El pase de diapositivas requiere JavaScript.

Posterior a esto, debemos abrir el archivo Properties del proyecto UWP, una vez hecho esto en la pestaña de Aplicación (Application) seleccionemos la opción Manifiesto del paquete (Package Manifest).

demo10

Una ves en el manifiesto, ubiquemos la pestaña de Capacidades (Capabilities) ya que deberemos de seleccionar y habilitar la Cámara Web (WebCam).

demo11

Ahora guardemos y cerremos el archivo. Ejecutemos y veamos el resultado:

El pase de diapositivas requiere JavaScript.

Con esto hemos terminado, ahora ya tenemos una app hecha en Xamarin.Forms utilizando los MS Cognitive Services – Emotion.

Agradezco a mi amigo Fernando Chiquiza (@fchiquiza) por brindarse como voluntario en esta prueba, y a Luis Beltran por su apoyo en la realización de este material.

Mas información :

Si gustan acceder a la solución completa de este ejemplo, la pueden descargar desde aquí.

githubgallery

Anuncios

1 thought on “Microsoft Cognitive Services [Emotions.API && Xamarin.Forms] DEMO”

Responder

Por favor, inicia sesión con uno de estos métodos para publicar tu comentario:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s