[Actor Studio] Cognitive Services et Face API
Dans notre premier article, nous avions découvert l’application qui nous a servi à animer le stand SOAT durant les MS Experiences ’18.
Nous étions ensuite entrés un peu plus dans le code pour découvrir comment capter le flux vidéo de la caméra, l’afficher, détecter des visages en mode offline et les superposer au flux vidéo.
Je vous propose désormais de mettre les mains un peu plus dans le cambouis en découvrant comment les Cognitive Services de Microsoft vont nous permettre d’analyser les visages.
Cognitive Services
Les services cognitifs de Microsoft regroupent un ensemble d’APIs permettant d’ajouter de l’intelligence à vos scénarios business pour comprendre les besoins de vos utilisateurs grâce à des algorithmes intelligents.
Pour chacune de ces API, de nombreux SDK, disponibles dans plusieurs langages, permettent de les consommer pour vous permettre d’ajouter rapidement et simplement de l’intelligence à vos applications.
Les Cognitive Services vont donc nous permettre :
- D’analyser une image avec Computer Vision
- De faire de la reconnaissance vocale avec le service Speech
- D’obtenir les intentions avec LUIS
- De détecter la langue et d’analyser des sentiments avec Text Analysis
- D’obtenir des requêtes web pertinentes avec la recherche Web Bing
- D’obtenir des requêtes d’images pertinentes avec Recherche d’images Bing
Dans notre scénario Actor Studio, notre objectif est de :
- reconnaître des émotions
- reconnaître des visages, ou tout du moins le visage le plus ressemblant
Pour ces deux activités, la brique nécessaire est donc Computer Vision et une seule API est nécessaire : l’API Visage ou Face API.
Face API
Créer la ressource depuis le portail Azure
Pour travailler avec l’API, nous devons commencer par créer une ressource dans le portail Azure.
L’API Visage (ou Face API) qui nous intéresse est une sous-API du service cognitif Vision.
Pour commencer il vous faut aller sur la page des services cognitifs, sélectionner l’API Vision et cliquer sur Obtenir la clé API de l’API Visage :
L’utilisation des services cognitifs se fait en liant la ressource à votre compte Azure existant, mais est également accessible gratuitement pendant 7 jours.
Vous pourrez donc utiliser votre compte Microsoft, Facebook, Linkedin ou Github pour demander une clé d’API gratuite et valable 7 jours.
Extraire la clé d’API
Une fois votre requête validée, vous pourrez voir votre API disponible.
Deux informations sont importantes dans cette page.
- Point de terminaison (endpoint) : correspond à l’URL de l’API
- Clé : correspond à l’identification de votre API sur cet endpoint
Notez bien ces éléments, et notamment la région dans laquelle se trouve votre API.
Ajouter le SDK à votre application
Comme je vous le disais dans la présentation des services cognitifs de Microsoft, la force de ces API est leur nombre, mais surtout la disponibilité pour chacune d’entre elles de SDK disponibles pour plusieurs langages.
L’API Visage n’échappe pas à la règle et propose des SDK en C#, Java, Node.js, Python et même Go.
Dans cet article, nous présenterons le code utilisant le SDK C# mais les mêmes fonctionnalités seraient exploitables depuis un autre langage, donc ne boudez pas votre plaisir.
Il faut également noter que plusieurs versions du SDK existent, face aux différentes versions de l’API. Dans notre application, nous nous basons sur la dernière version de l’API et donc sur le SDK en version v2.0.0-preview.
Pour ajouter le SDK dans notre projet UWP, nous avons décidé de créer un projet à part, servant de proxy à l’API Azure et l’application UWP. Ce découpage apporte de la clarté à notre code mais permet également de bien dissocier les responsabilités de chaque composant pour apporter de la flexibilité à notre code.
Dans ce projet, nommé [FaceApiProxy] nous avons donc ajouté une référence via Nuget au SDK de FaceAPI.
IFaceClient
Une fois ce SDK ajouté, nous pouvons commencer par initialiser le client.
Pour cela, il existe un objet de type FaceClient
implémentant l’interface IFaceClient
. Rien de plus simple me direz-vous !
En réalité il existe quelques subtilités à connaître :
- l’objet
FaceClient
prend, dans son constructeur, un objetApiKeyServiceClientCredentials
qui devra être intialisé avec la clé d’API récupérée via le portail Azure - il existe une URL Endpoint spécifique pour chaque région, il faut donc bien faire attention à la région dans laquelle nous avons créé la ressource Face API dans Azure
- l’
Endpoint
URL n’est pas sous le même format, selon que vous utilisiez la version 1 ou la version 2 de l’API
Dans cet article nous utiliserons la dernière version de l’API, encore en preview.
L’Endpoint d’accès n’est donc pas celui fourni sur la page Azure (v1.0) mais au format suivant :
https://{FaceApiKeyRegion}.api.cognitive.microsoft.com/
Dans le cas d’une Face API créée dans la région WestEurope, l’endpoint ressemblera donc à :
https://westeurope.api.cognitive.microsoft.com/
Le code de création du client est le suivant :
var cognitiveServicesCredentials = new ApiKeyServiceClientCredentials(FaceApiKey);
var faceClient = new FaceClient(cognitiveServicesCredentials)
{
Endpoint = $"https://{FaceApiKeyRegion}.api.cognitive.microsoft.com/";
};
Si vous vous trompez dans ces paramètres, des exceptions seront levées (ex: NotFound) mais uniquement au premier appel concret à l’API et non lors de l’initialisation du client. Dangereux donc, et plus difficile à déceler !
Détection de sourire
Lors de MS Experiences ’18, notre programme demandait au visiteur de lui sourire dans le but d’engager le workflow de l’animation. Cette détection de sourire est le fruit d’un apprentissage par Microsoft d’énormes bases de données de visages introduites dans un modèle, par la suite entraîné pour y déceler des sourires ou d’autres caractéristiques de visages.
C’est cette détection de sourire que nous allons implémenter aujourd’hui.
Nous avons provisionné notre ressource Azure de Face API et nous avons ajouté le SDK à notre application. Il ne nous reste plus qu’à utiliser concrètement ce service depuis notre application.
Extraction d’image du flux vidéo
Dans le dernier article nous avions vu comment capter et afficher le flux vidéo depuis un élément MediaCapture
.
Dans cet article nous allons extraire une image de ce flux pour l’envoyer à l’API.
Pour extraire une image du flux vidéo, il faut utiliser la méthode GetPreviewFrameAsync
de l’objet MediaCapture
. Cette méthode peut prendre en paramètre un objet VideoFrame
qui servira de destination et dont nous pouvons définir le format. Cela nous sera très utile pour obtenir une image légère et donc optimiser les appels réseau :
// define size for destination frame
double scale = 480d / previewProperties.Height;
VideoFrame videoFrame = new VideoFrame(BitmapPixelFormat.Bgra8, (int)(previewProperties.Width * scale), 480);
using (var frame = await VideoCapture.GetPreviewFrameAsync(videoFrame))
{
...
}
Une fois cet objet VideoFrame
récupéré, il faut en extraire un stream que nous pourrons fournir au SDK. Pour cela nous utiliserons l’objet BitmapEncoder
et la méthode CreateAsync
qui prend en entrée le stream et un id d’encoder (ici Jpeg) :
if (frame.SoftwareBitmap != null)
{
var bitmap = frame.SoftwareBitmap;
InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream();
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
encoder.SetSoftwareBitmap(bitmap);
await encoder.FlushAsync();
...
}
Appel de Face API via le SDK
Nous avons notre stream d’image, il faut désormais le fournir à notre SDK afin qu’il envoie cette image au service cognitif et que celui-ci nous renvoie le résultat de son analyse.
Avant cela nous devons lui indiquer ce que nous attendons comme analyse.
Cela se fait avec un tableau de FaceAttributeType
.
L’énumérateur FaceAttributeType
peut prendre plusieurs valeurs :
public enum FaceAttributeType
{
Age = 0,
Gender = 1,
HeadPose = 2,
Smile = 3,
FacialHair = 4,
Glasses = 5,
Emotion = 6,
Hair = 7,
Makeup = 8,
Occlusion = 9,
Accessories = 10,
Blur = 11,
Exposure = 12,
Noise = 13
}
Vous l’aurez compris, vous pouvez demander à votre API de détecter un bon nombre de caractéristiques mais également d’alléger le traitement en ne fournissant que les attributs qui vous intéressent. En l’occurence nous ne nous intéressons qu’à la détection du Smile
.
var requiredFaceAttributes = new[] { FaceAttributeType..Smile };
Nous pouvons alors utiliser la méthode DetectWithStreamAsync
de notre SDK :
var detect = await faceClient.Face.DetectWithStreamAsync(
stream.AsStream(), false, false,
requiredFaceAttributes);
Une fois le résultat obtenu, nous pouvons analyser le visage le plus grand et obtenir un résultat de confiance, de 0 à 1, sur le fait que cette personne sourit ou non ( 0 : la personne ne sourit pas / 0.5 : nous ne sommes pas sûrs / 1 : la personne sourit assurément) :
if (detect.Any())
{
var biggestFace = detect.OrderByDescending(f => f.FaceRectangle.Height * f.FaceRectangle.Width).First();
if (biggestFace.FaceAttributes.Smile > 0.5)
{
// Raise an event 'SmileDetected'
SmileDetected?.Invoke(this, biggestFace);
}
}
Émotions
Dans notre animation, une autre fonctionnalité importante, si ce n’est LA plus importante était la détection d’émotions.
Nous demandions au visiteur de jouer 4 émotions que nous soumettions au service de détection de Microsoft pour obtenir un score “Actor Studio”.
Ce score est en réalité un indice de confiance remonté par l’API Visage sur la détection de l’émotion ciblée.
Pour détecter une émotion, il nous suffit d’utiliser la même API et donc la même méthode que pour le sourire.
La seule différence entre nos deux appels est le paramètre returnFaceAttributes
qui, pour le coup ne comportera qu’un objet FaceAttributeType.Emotion
.
var requiredFaceAttributes = new[] { FaceAttributeType.Emotion };
var response = await faceClient.Face.DetectWithStreamAsync(faceStream, true, true, requiredFaceAttributes);
Si l’on souhaite récupérer le résultat de détection d’émotion pour le premier visage détecté, le code sera le suivant :
return response?.FirstOrDefault()?.FaceAttributes?.Emotion;
Cet objet de type Microsoft.Azure.CognitiveServices.Vision.Face.Models.Emotion
contient en réalité une liste des émotions reconnaissables par le service. Pour chacune de ces émotions, un score de confiance de détection ou non est disponible sous forme de double.
Pour savoir si la joie est détectée par exemple, nous utiliserons le résultat Hapiness
, pour la peur, Anger
, etc.
Nous avons un peu détourné le système, mais c’est ainsi que nous avons pu demander à l’utilisateur de jouer une émotion, capturer une photo, l’envoyer à l’API et vérifier quelle était la confiance du service dans la détection de cette émotion précise.
Optimiser la facture
Restreindre les appels
Vous vous en doutez, il est inutile d’appeler le service FaceAPI si aucun visage n’est détecté dans le flux vidéo, ou si le visage le plus proche est trop petit (utilisateur éloigné donc détection plus fastidieuse).
Dans l’article précédent, nous avions vu comment ajouter une détection de visages grâce aux filtres et aux événements.
C’est donc dans cette même méthode FaceDetectionEffect_FaceDetected
que nous allons ajouter la détection de sourire en appelant notre nouvelle méthode CheckSmileAsync
:
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => await CheckSmileAsync());
Globalement il est nécessaire de restreindre les appels au strict minimum pour éviter de faire des appels inutiles, et donc de gâcher votre quota.
Il faut également ajouter de la robustesse à votre application pour réagir aux erreurs liées aux quotas d’utilisation de l’API en mettant en place une politique de retry ou de cancel des appels.
Conclusion
Dans cet article, nous avons découvert comment provisionner un des services cognitifs Azure, nommé Face API, et comment cette API nous permet de détecter les visages dans une image.
Nous avons également découvert comment détecter des sourires, des émotions ou toute autre caractéristique dans ces visages via un SDK simple.
Nous avons donc vu plusieurs usages de ce service dans notre animation, en détectant les sourires et les émotions dans un scénario ludique. Mais les applications plus concrètes de ce service sont nombreuses, notamment dans l’évènementiel, les jeux ou le retail. Il ne vous reste qu’à vous lancer.
Ce service est utilisable gratuitement pendant 7 jours, alors ne vous privez pas !
© SOAT
Toute reproduction est interdite sans autorisation de l’auteur.