Novembre 2016

Volume 31, numéro 11

Cet article a fait l'objet d'une traduction automatique.

Cognitive Services : découvrir le monde avec Xamarin et les API Vision par ordinateur de Microsoft

Par Alessandro Del Del

Dans mon dernier article, j’ai fourni une brève introduction aux Services Microsoft Cognitive, décrivant les API RESTful disponibles et illustrant la Face et émotion API dans une application interplateforme écrite avec Xamarin.Forms et c# (msdn.microsoft.com/magazine/mt742868). Dans cet article, j’aborderai une autre ensemble important d’API, appelé Vision de l’ordinateur. Vous voudrez lire l’article précédent avant de continuer avec celle-ci, car je vais supposer que vous êtes familiarisé avec quelques concepts sur les Services Cognitive, que j’ai expliqué il, et parce que je vais réutiliser certains packages NuGet et extraits de code à partir de l’exemple d’application précédent. Cela étant dit, commençons par décrire les API de Vision ordinateur Microsoft.

Mise en route avec les API de Vision de l’ordinateur

Les API de Vision ordinateur autoriser les images à être décrits et analysés à l’aide du langage naturel. Vous pouvez exporter une image vers le service Vision par ordinateur ou pointer vers l’URL d’une image, et vous attendre à obtenir une description naturelle, sans avoir à la développer et la mettre en forme. Et ce n'est pas tout. Vision de l’ordinateur peut effectuer la reconnaissance optique de caractères (OCR) sur une image qui contient du texte, et il peut analyser une image afin de détecter les faces des célébrités. Comme avec d’autres services Computer Vision est basée sur l’apprentissage et prend en charge de REST, ce qui signifie que vous effectuez des requêtes HTTP et obtenez une réponse JSON. Le code JSON Figure 1 présente un extrait de la réponse de l’analyse de la Vision de l’ordinateur sur une image, tirée de la documentation officielle à bit.ly/2a45kQI.

Figure 1 résultat de l’analyse de Vision d’une Image d’ordinateur

{
  "description": {
    "tags": [
      "person",
      "man",
      "outdoor",
      "window",
    ],
    "captions": [
      {
        "text": "Satya Nadella sitting in front of a building",
        "confidence": 0.38035155997373377
      }
    ]
  },
  "requestId": "ed2de1c6-fb55-4686-b0da-4da6e05d283f",
  "metadata": {
    "width": 1500,
    "height": 1000,
    "format": "Jpeg"
  }
}

Comme vous pouvez le voir, la réponse contient une description de langage naturel de ce que fait une célébrité dans l’image, avec une liste de balises et taille de l’image et le format des informations supplémentaires. Et c’est seulement certaines des informations que vous pouvez obtenir à partir du service de la Vision de l’ordinateur.

Exécution HTTP demande certainement fonctionne, mais en tant que développeur .NET, vous pouvez préférer une approche différente. Comme avec la Face et les API émotion, Microsoft propose également une bibliothèque client portable (PCL) de Vision d’ordinateur que vous pouvez utiliser dans vos applications c#, y compris .NET et Xamarin, ce qui vous permet d’appeler le service par le biais des méthodes pratiques à l’aide d’une approche orientée objet. Je vais utiliser cette bibliothèque sous peu.

S’abonner à l’API de Vision ordinateur

Comme avec d’autres Services Cognitive, pour utiliser les API de Vision d’ordinateur, vous devez inscrire le service obtenir une clé secrète à utiliser dans votre code. Pour ce faire, il suffit d’accéder à la page Abonnements (bit.ly/2b2rKDO) et demande une nouvelle version d’évaluation de l’API de Vision ordinateur. Figure 2 montre comment votre abonnement s’affiche après l’inscription.

Inscription pour les API de Vision ordinateur
Figure 2 l’inscription pour les API de Vision ordinateur

Comme vous pouvez le voir, vous obtenez deux clés secrètes. Vous aurez besoin un plus tard lorsqu’il est temps d’écrire du code c#.

Création d’une application Xamarin.Forms et installation des Packages NuGet

Lancez Visual Studio 2015 et créez un nouveau projet Xamarin.Forms utilisant le modèle de projet application XAML vierge (Xamarin.Forms Portable). Appelez le projet ComputerVisionSample et cliquez sur OK. Lorsque vous êtes prêt, installez les packages NuGet suivants :

Microsoft.ProjectOxford.Vision installe la bibliothèque cliente pour les API de Vision ordinateur et doit être installé pour seulement le projet PCL.

Xam.Plugin.Connectivity contient la connectivité plug-in pour Xamarin.Forms et doit être installé pour tous les projets dans la solution. Il servira à vérifier pour une connexion réseau avant de tenter d’effectuer des demandes via Internet.

Xam.Plugin.Mediacontains le support de plug-in pour Xamarin.Forms et doit être installé pour tous les projets dans la solution. Il servira à prendre et sélectionnez les images à partir de code partagé, au lieu de devoir écrire du code spécifique à la plateforme.

Vérifiez que vous générez la solution à ce stade, afin que toutes les références seront actualisées. Maintenant plongeons-nous dans les API de Vision ordinateur, analyse les trois principaux scénarios.

Décrivant les images avec les API d’analyse

La bibliothèque cliente Computer Vision expose une classe appelée Microsoft.ProjectOxford.Vision.VisionServiceClient, qui est l’objet vous permet d’envoyer des demandes au service et qui expose les propriétés contenant le résultat de l’analyse. Cette classe est utilisée dans tous les scénarios de que cibler. Le premier scénario décrit images, par laquelle on entend obtenir une description de ce que représente l’image, en fonction de langage naturel et lisible. La réponse renvoie le service contient également des informations, telles que les couleurs dominantes, faces détectés, balises, le type d’image et taille, et si une image contient également un contenu pour adultes ou desseins malveillants, comme. Pour décrire une image, la classe VisionServiceClient expose deux méthodes : AnalyzeImageAsync et DescribeAsync. Ce dernier fournit un plus petit ensemble d’informations et est généralement utilisé pour récupérer uniquement une description du langage naturel de l’image, tandis que AnalyzeImageAsync renvoie que des informations plus détaillées. Les deux méthodes stockent leur réponse dans un objet de type Microsoft.ProjectOxford.Vision.Contract.AnalysisResult. Dans cet article, je vais utiliser AnalyzeImageAsync. Cette méthode possède deux surcharges, une acceptation d’un flux de données et une acceptation d’une URL pointant vers une image. les deux surcharges nécessitent pour spécifier le jeu d’informations que vous voulez récupérer à partir de l’image. Cet ensemble d’informations est représenté par un tableau de valeurs de l’énumération Microsoft.ProjectOxford.Vision.VisualFeature. Dans la page MainPage.xaml de l’exemple d’application, je vais implémenter la description de l’image. Figure 3 montre comment implémenter une méthode d’analyse détaillée.

Figure 3 l’analyse d’une image de Description

private async Task<AnalysisResult> AnalyzePictureAsync(Stream inputFile)
{
  // Use the connectivity plug-in to detect
  // if a network connection is available
  // Remember using Plugin.Connectivity directive
  if (!CrossConnectivity.Current.IsConnected)
  {
    await DisplayAlert("Network error",
      "Please check your network connection and retry.", "OK");
    return null;
  }
  VisualFeature[] visualFeatures = new VisualFeature[] { VisualFeature.Adult,
    VisualFeature.Categories, VisualFeature.Color, VisualFeature.Description,
    VisualFeature.Faces, VisualFeature.ImageType, VisualFeature.Tags };
  AnalysisResult analysisResult =
    await visionClient.AnalyzeImageAsync(inputFile,
    visualFeatures);
  return analysisResult;           
}

Notez comment le code utilise la connectivité plug-in pour détecter une connexion réseau, comme expliqué dans mon article précédent. Il existe trois points clés dans Figure 3. Le premier point concerne les informations que vous souhaitez récupérer. Le tableau de valeurs de VisualFeature contient la liste plus détaillée des informations que possible et inclut les valeurs de l’énumération VisualFeature. Ils ont des noms explicites et incluent la détection de contenu pour adultes et desseins malveillants, comme, une liste de catégories de l’image, les couleurs dominantes, une description du langage naturel, une liste des faces, des informations sur l’image et une liste de balises. J’ai inclus la valeur de Faces par souci d’exhaustivité, mais je n’en fait utiliser ce résultat, car vous pouvez récupérer des informations plus détaillées sur la face à l’aide de l’API de Face. Le deuxième point clé est l’appel à AnalyzeImageAsync, qui envoie un flux de données pour le service ainsi que la liste des informations que vous souhaitez récupérer, puis stocke la réponse dans un objet de type AnalysisResult. Cette classe est le troisième point clé et qu’il est définie dans Figure 4.

Figure 4 la définition de classe de AnalysisResult

namespace Microsoft.ProjectOxford.Vision.Contract
{
  public class AnalysisResult
  {
    public AnalysisResult();
    public Adult Adult { get; set; }
    public Category[] Categories { get; set; }
    public Color Color { get; set; }
    public Description Description { get; set; }
    public Face[] Faces { get; set; }
    public ImageType ImageType { get; set; }
    public Metadata Metadata { get; set; }
    public Guid RequestId { get; set; }
    public Tag[] Tags { get; set; }
  }
}

Pour afficher cette définition, cliquez sur le type de AnalysisResult dans l’éditeur de code, puis sélectionnez Atteindre la définition (ou Aperçu de définition si vous ne souhaitez pas laisser la fenêtre active). Comme vous pouvez le voir, la définition expose les propriétés qui contiennent les informations requises par le biais des objets spécialisés. En utilisant atteindre la définition de chaque type de propriété, vous pouvez comprendre comment chaque objet spécialisé est définie et, par conséquent, comment vous pouvez l’utiliser dans votre application (avec une liaison de données, par exemple). Par exemple, le type de la Description est défini comme suit :

public class Description
{
  public Description();
  public Caption[] Captions { get; set; }
  public string[] Tags { get; set; }
}

Ici, la propriété la plus importante est légendes, un tableau d’objets de la légende. Chaque légende contient une description lisible le service à récupérer à partir de l’image, ce qui est proposé via sa propriété Text. La classe adulte est définie comme suit :

public class Adult
 {
   public Adult();
   public double AdultScore { get; set; }
   public bool IsAdultContent { get; set; }
   public bool IsRacyContent { get; set; }
   public double RacyScore { get; set; }
 }

Ceci est une classe simple et expose deux propriétés bool qui retournent la valeur true si l’image contient du contenu pour adultes ou desseins malveillants, comme, ainsi que deux autres propriétés qui représentent le niveau de confiance pour le résultat. Ceci est particulièrement utile lorsque vous souhaitez limiter la disponibilité du contenu. Examinons maintenant la définition de la classe de couleur :

public class Color
{
  public Color();
  public string AccentColor { get; set; }
  public string DominantColorBackground { get; set; }
  public string DominantColorForeground { get; set; }
  public string[] DominantColors { get; set; }
  public bool IsBWImg { get; set; }
}

Cette classe est utilisée pour stocker une liste de couleurs détectée dans l’image, comme la couleur d’accentuation, dominant au premier plan et couleurs d’arrière-plan et un tableau de couleurs dominantes. Il expose également une propriété appelée IsBWImg, de type booléen, qui renvoie true si l’image est noir et blanc. Comprendre comment ces objets sont définis et les propriétés qu’ils exposent aidera lorsque vous souhaitez présenter des informations dans l’interface Utilisateur via la liaison de données. Je vais laisser pour Explorer la définition des classes AnalysisResult utilise pour stocker les informations d’analyse. Comme il s’agit, l’instance AnalysisResult peut être lié aux données à certains éléments d’interface Utilisateur pour afficher des informations très facilement et j’y reviendrai bientôt. Considérez Figure 5, qui affiche la liste complète pour le code XAML est requis pour définir l’interface Utilisateur de l’exemple d’application.

Figure 5 la définition de l’interface Utilisateur pour la Description de l’Image

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ComputerVisionSample"
             x:Class="ComputerVisionSample.MainPage">
  <StackLayout Orientation="Vertical">
    <Button x:Name="TakePictureButton" Clicked="TakePictureButton_Clicked"
      Text="Take from camera"/>
    <Button x:Name="UploadPictureButton" Clicked="UploadPictureButton_Clicked"
      Text="Pick a photo"/>
    <ActivityIndicator x:Name="Indicator1" IsVisible="False" IsRunning="False" />
    <Image x:Name="Image1" HeightRequest="240" />
  <ScrollView Padding="10">
    <StackLayout>
      <StackLayout Orientation="Horizontal">
        <Label Text="Adult content: "/>
        <Label Text="{Binding Adult.IsAdultContent}"/>
      </StackLayout>
      <StackLayout Orientation="Horizontal">
        <Label Text="Racy content: "/>
        <Label Text="{Binding Adult.IsRacyContent}"/>
      </StackLayout>
      <StackLayout Orientation="Horizontal">
        <Label Text="Description: "/>
        <Label Text="{Binding Description.Captions[0].Text}"/>
      </StackLayout>
      <StackLayout Orientation="Horizontal">
        <Label Text="Accent color: "/>
        <Label Text="{Binding Color.AccentColor}"/>
      </StackLayout>
      <StackLayout Orientation="Horizontal">
        <Label Text="Tags: "/>
        <ListView ItemsSource="{Binding Tags}">
          <ListView.ItemTemplate>
            <DataTemplate>
              <ViewCell>
                <Label Text="{Binding Name}"/>
              </ViewCell>
            </DataTemplate>
          </ListView.ItemTemplate>
        </ListView>
      </StackLayout>      
    </StackLayout>
  </ScrollView>
</ContentPage>

L’interface Utilisateur définit deux boutons, une zone pour sélectionner une image à partir de l’appareil et l’autre pour prendre une photo à partir de l’appareil photo, ainsi qu’un ActivityIndicator qui montre qu’une opération est en cours. L’image sélectionnée s’affiche dans un contrôle Image. (J’ai utilisé ces contrôles dans l’article précédent, trop.) Notez que la liaison de données est exprimée dans les contrôles Label. Par exemple, vous pouvez lier la propriété de texte directement à Adult.IsAdultContent et Adult.IsRacyContent à partir de l’instance AnalysisResult au lieu d’effectuer les liaisons complexes. De même, vous pouvez récupérer la description de langage naturel d’une image par une liaison directement à la propriété Text du premier objet de légende dans la collection de légendes exposée par la propriété AnalysisResult.Description. Bien entendu, cela convient s’il en existe qu’une légende ou si vous souhaitez simplement afficher le premier résultat. Toutefois, des légendes peuvent contenir plusieurs objets de la légende et, dans ce cas, vous souhaiterez choisir une liaison de données différent. La même liaison directe est effectuée par rapport à la propriété Color.AccentColor. Pour les balises, l’interface Utilisateur affiche la liste des balises avec un contrôle ListView, avec un modèle de données qui présente une étiquette pour chaque nom de la balise. Dans le code-behind, vous devez d’abord implémenter deux gestionnaires d’événements pour les boutons, comme indiqué dans Figure 6. Le code utilise le support plug-in, j’ai déjà décrite dans mon article précédent, donc je n’aborderai pas il ici.

Figure 6 un clic sur les gestionnaires d’événements pour les boutons

private async void TakePictureButton_Clicked(object sender, EventArgs e)
{
  await CrossMedia.Current.Initialize();
  if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
  {
    await DisplayAlert("No Camera", "No camera available.", "OK");
    return;
  }
  var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
  {
    SaveToAlbum = true,
    Name = "test.jpg"
  });
  if (file == null)
      return;
  this.Indicator1.IsVisible = true;
  this.Indicator1.IsRunning = true;
  Image1.Source = ImageSource.FromStream(() => file.GetStream());
  var analysisResult = await AnalyzePictureAsync(file.GetStream());
  this.BindingContext = analysisResult;
  this.Indicator1.IsRunning = false;
  this.Indicator1.IsVisible = false;
}
private async void UploadPictureButton_Clicked(object sender, EventArgs e)
{
  if (!CrossMedia.Current.IsPickPhotoSupported)
  {
    await DisplayAlert("No upload", "Picking a photo is not supported.", "OK");
    return;
  }
  var file = await CrossMedia.Current.PickPhotoAsync();
  if (file == null)
      return;
  this.Indicator1.IsVisible = true;
  this.Indicator1.IsRunning = true;
  Image1.Source = ImageSource.FromStream(() => file.GetStream());
  var analysisResult = await AnalyzePictureAsync(file.GetStream());
  this.BindingContext = analysisResult;
  this.Indicator1.IsRunning = false;
  this.Indicator1.IsVisible = false;
}

Le point clé ici est l’appel de la méthode AnalyzePictureAsync, dont le résultat (une instance de AnalysisResult) est attribuée à la page comme source de données. Cela permet la liaison de données des éléments de l’interface Utilisateur dans Figure 6. Ensuite, vous devez déclarer et instancier la classe VisionServiceClient comme suit :

private readonly VisionServiceClient visionClient;
public MainPage()
{
  InitializeComponent();
  this.visionClient =
    new VisionServiceClient("YOUR-KEY-GOES-HERE");
}

Notez que vous devez fournir une des clés secrètes que vous avez obtenu lors de l’inscription pour les API de Vision d’ordinateur. Enfin, n’oubliez pas d’ajouter les autorisations appropriées dans les manifestes de l’application. Par exemple, le projet de plate-forme de Windows universelle (UWP) requiert les fonctionnalités Internet, Webcam et bibliothèque d’images ; et le projet Android nécessite les autorisations INTERNET, APPAREIL PHOTO, READ_EXTERNAL_STORAGE et WRITE_EXTERNAL_STORAGE. Vous pouvez maintenant démarrer l’application sur votre périphérique préféré ou un émulateur. Figure 7 indique la version UWP s’exécutant en mode bureau, avec une image et les informations demandées.

Qui décrit une image avec les API de Vision de l’ordinateur
Figure 7 décrivant une image à l’ordinateur de Vision API

Parmi toutes les informations disponibles, vous aurez probablement plus impressionnés par le contenu de la propriété Description de la classe AnalysisResult, qui fournit une description lisible, généré automatiquement sans aucun effort.

Récupération de texte dans les images avec la reconnaissance optique de caractères

Reconnaissance optique de caractères est la conversion électronique d’une image de texte en texte modifiable. La plupart des scanneurs sont livrés avec logiciel de reconnaissance optique de caractères qui vous permet de générer des documents modifiables à partir d’images contenant du texte, tels que des pages de magazines. L’ensemble d’API de Vision ordinateur offre un service de reconnaissance optique de caractères qui peut récupérer du texte dans les images, quelle que soit la langue du texte. OCR entraîne essentiellement des objets string. Pour comprendre comment fonctionnent les APIs OCR, nous allons ajouter une nouvelle page XAML au projet PCL. Dans l’Explorateur de solutions, cliquez sur le projet de ComputerVisionSample (Portable), sélectionnez Ajouter | Un nouvel élément, puis dans la boîte de dialogue Ajouter un nouvel élément, sélectionnez l’élément de Forms Xaml Page disponible dans le nœud inter-plateformes. Appelez la nouvelle fenêtre OcrRecognitionPage. La classe VisionServiceClient expose une méthode appelée RecognizeTextAsync, qui effectue une reconnaissance optique de caractères sur une image. Cette méthode accepte un flux ou une URL pointant vers une image, et vous pouvez éventuellement spécifier la langue. Si vous ne spécifiez pas un langage, RecognizeTextAsync tente de détecter automatiquement la langue. Elle retourne un objet de type Microsoft.ProjectOxford.Vision.Contract.OcrResults, qui est un peu complexe et méritent une explication plus. À ce stade, prenons le code suivant, qui appelle le service de reconnaissance optique de caractères sur un flux et détecte automatiquement la langue :

private async Task<OcrResults> AnalyzePictureAsync(Stream inputFile)
{
  if (!CrossConnectivity.Current.IsConnected)
  {
    await DisplayAlert("Network error",
      "Please check your network connection and retry.", "OK");
    return null;
  }
  OcrResults ocrResult = await visionClient.RecognizeTextAsync(inputFile);
  return ocrResult;
}

Notez la façon dont vous commencez toujours par vérifier pour la connectivité réseau. Si vous souhaitez spécifier une langue, vous passez à RecognizeTextAsync une instance de la classe RecognizeLanguage, comme suit :

OcrResults ocrResult =
  await visionClient.RecognizeTextAsync(inputFile,
  new RecognizeLanguage(){ ShortCode = "it", LongName = "Italian"  }

L’application échantillon officiel pour WPF à bit.ly/2ahHum3 affiche la liste complète des codes et des langues prises en charge. La classe OcrResults est définie comme suit :

public class OcrResults
{
  public OcrResults();
  public string Language { get; set; }
  public string Orientation { get; set; }
  public Region[] Regions { get; set; }
  public double? TextAngle { get; set; }
}

Les propriétés de langue, l’Orientation et TextAngle représentent la langue détectée, l’orientation et l’angle du texte reconnu. Régions est un tableau d’objets de la région. Chaque région représente les domaines qui contiennent du texte sur l’image et le type de zone possède une propriété appelée lignes, un tableau d’objets, chacun représentant une seule ligne de texte dans la zone. Chaque objet possède une propriété appelée mots, un tableau d’objets de Word, chacune représentant un mot unique dans la ligne. Il s’agit d’une hiérarchie légèrement complexe, mais il fournit des résultats extrêmement précis dans la mesure où vous pouvez travailler avec tous les mots qui détecte l’API. N’oubliez pas d’utiliser atteindre la définition pour examiner la définition de chaque classe. En raison de cette complexité, certaines parties de l’interface Utilisateur seront générés au moment de l’exécution. Pour l’instant, dans le code XAML pour la nouvelle page, ajoutez le code indiqué dans Figure 8, qui déclare certaines familier contrôle (deux boutons, une Image, un ActivityIndicator) et a détecté un StackLayout qui recevront la liste de mots et de lignes. Notez comment le code ajoute également un contrôle Label pour afficher la langue détectée.

Figure 8 la préparation de l’interface Utilisateur pour la reconnaissance optique de caractères

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ComputerVisionSample.OcrRecognitionPage">
  <StackLayout Orientation="Vertical">
    <Button x:Name="TakePictureButton" Clicked="TakePictureButton_Clicked"
      Text="Take from camera"/>
    <Button x:Name="UploadPictureButton" Clicked="UploadPictureButton_Clicked"
      Text="Pick a photo"/>
    <ActivityIndicator x:Name="Indicator1" IsVisible="False" IsRunning="False" />
    <Image x:Name="Image1" HeightRequest="240" />
    <StackLayout Orientation="Horizontal">
      <Label Text="Language: "/>
      <Label Text="{Binding Language}"/>
    </StackLayout>
    <ScrollView>
      <StackLayout x:Name="DetectedText">
      </StackLayout>
    </ScrollView>
  </StackLayout>
</ContentPage>

Comme je l’ai mentionné, certaines parties de l’interface Utilisateur seront construits au moment de l’exécution. Plus précisément, j’ai besoin parcourir le groupe de régions, puis son tableau lignes imbriquée, de détecter tous les mots dans le tableau de mots. Cela est démontré dans Figure 9, où un StackLayout est généré pour chaque ligne.

Figure 9 itération des zones de texte et de lignes

private void PopulateUIWithRegions(OcrResults ocrResult)
{
  // Iterate the regions
  foreach (var region in ocrResult.Regions)
  {
    // Iterate lines per region
    foreach (var line in region.Lines)
    {
      // For each line, add a panel
      // to present words horizontally
      var lineStack = new StackLayout
      { Orientation = StackOrientation.Horizontal };
      // Iterate words per line and add the word
      // to the StackLayout
      foreach (var word in line.Words)
      {
        var textLabel = new Label { Text = word.Text };
        lineStack.Children.Add(textLabel);
      }
      // Add the StackLayout to the UI
      this.DetectedText.Children.Add(lineStack);
    }
  }
}

Le reste du code est très simple. Tout d’abord, déclarez et instanciez la classe VisionServiceClient comme suit :

private readonly VisionServiceClient visionClient;
public OcrRecognitionPage()
{
  InitializeComponent();
  this.visionClient =
    new VisionServiceClient("YOUR-KEY-GOES-HERE");
}

Vous pouvez certainement utiliser la même clé que vous avez utilisée précédemment. Ensuite, vous pouvez réutiliser les deux gestionnaires d’événements illustrées Figure 6, où vous devez remplacer les lignes suivantes :

var analysisResult = await AnalyzePictureAsync(
  file.GetStream());
this.BindingContext = analysisResult;

avec les nouvelles lignes suivantes :

var ocrResult = await AnalyzePictureAsync(
  file.GetStream());
this.BindingContext = ocrResult;
PopulateUIWithRegions(ocrResult);

En procédant ainsi, vous pouvez lier l’instance OcrResults à l’interface Utilisateur et ensuite la méthode PopulateUIWithRegions génère de nouvelles lignes avec le texte détecté. Par souci de simplicité, au lieu d’implémenter la navigation entre les pages, vous pouvez simplement modifier la page de démarrage dans le constructeur App.xaml.cs comme suit :

MainPage = new OcrRecognitionPage();

Maintenant, l’application en choisissant votre émulateur favori ou votre périphérique. Si vous sélectionnez ou prenez une photo, vous serez en mesure de lire le texte à imprimer, comme dans Figure 10.

Exécution de reconnaissance optique de caractères sur une Image
Figure 10 effectuant la reconnaissance optique de caractères sur une Image

Dans ce cas, l’exemple d’application est en cours d’exécution sur l’émulateur Android. Notez comment le langage a été correctement détecté comme anglais (en). Il est très important de noter que le service OCR fonctionne parfaitement avec les images de grande qualité. Si la résolution de l’image est faible, l’image est floue ou il contient du texte manuscrit ou liée, le service peut retourner un résultat inexact. Il est également important de mentionner que le service de reconnaissance optique de caractères peut détecter des mots même sur les images avec un arrière-plan de couleur multiples, pas seulement une couleur unie. Par exemple, vous pouvez analyser le texte sur l’image d’un coucher du soleil.

Recherche des célébrités avec un modèle spécifique à un domaine

Dans la première partie de cet article, j’ai expliqué ce que l’API de Vision ordinateur offrent décrire une image. La description est quelque chose qui se produit à un niveau très élevé et renvoie des informations générales de l’image. Microsoft travaille également sur offre spécialisée reconnaissance via les soi-disant modèles spécifique au domaine. Ils permettent le retour d’informations très spécifiques à partir d’une image, qui peut être combiné avec une description de l’image. Actuellement, le modèle de domaine spécifique uniquement disponible est reconnaissance des célébrités. À l’aide de ce modèle, vous pouvez tirer parti de l’API de Vision ordinateur pour détecter des célébrités dans une image. En règle générale, avec un modèle, vous pouvez effectuer analyse spécialisés dans des catégories spécifiques d’images. Par conséquent, mon exemple dernière consiste à reconnaître célébrités au sein des images. Impossible d’afficher les images célébrités pour des raisons de droits d’auteur, mais vous n’aurez aucun problème de test du code. Commençons par ajouter une nouvelle page XAML au projet PCL, appelé CelebrityRecognitionPage. Reportez-vous à la section précédente pour les étapes requises pour ajouter une page. L’interface Utilisateur de cette page est très simple : Il a juste besoin d’afficher le nom des célébrités dans une étiquette et, bien sûr, il propose les éléments d’interface Utilisateur habituelles, comme indiqué dans Figure 11.

Figure 11 Préparation de l’interface Utilisateur pour la reconnaissance des célébrités

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ComputerVisionSample.CelebrityRecognitionPage">
  <StackLayout Orientation="Vertical">
    <Button x:Name="TakePictureButton" Clicked="TakePictureButton_Clicked"
      Text="Take from camera"/>
    <Button x:Name="UploadPictureButton" Clicked="UploadPictureButton_Clicked"
      Text="Pick a photo"/>
    <ActivityIndicator x:Name="Indicator1" IsVisible="False" IsRunning="False" />
    <Image x:Name="Image1" HeightRequest="240" />
    <Label x:Name="CelebrityName"/>
  </StackLayout>
</ContentPage>

Reconnaissance des célébrités est effectuée à l’aide d’une méthode à partir de la classe VisionServiceClient appelée AnalyzeImageInDomainAsync. Cette méthode requiert l’utilisation de flux d’image ou URL et le modèle spécifique à un domaine pour la détection. Vous pouvez récupérer la liste des modèles disponibles en appelant le VisionServiceClient.ListModelsAsync ; Cependant, comme je l’ai mentionné, uniquement le modèle de reconnaissance célébrités est disponible pour le moment. Le code suivant montre comment récupérer la liste des modèles et un modèle spécifique :

private async Task<Model> GetDomainModel()
{
  ModelResult modelResult = await visionClient.ListModelsAsync();
  // At this writing, only celebrity recognition
  // is available. It is the first model in the list
  return modelResult.Models.First();
}

L’étape suivante est le code qui effectue la reconnaissance, comme dans la méthode personnalisée suivante appelée AnalyzePictureAsync :

private async Task<AnalysisInDomainResult> AnalyzePictureAsync(Stream inputFile)
{
  if (!CrossConnectivity.Current.IsConnected)
  {
    await DisplayAlert("Network error",
      "Please check your network connection and retry.", "OK");
    return null;
  }
  AnalysisInDomainResult analysisResult =
    await visionClient.AnalyzeImageInDomainAsync(inputFile, await GetDomainModel());
  return analysisResult;
}

Le résultat de l’analyse de l’image est un objet de type AnalysisInDomainResult avec la définition suivante :

public class AnalysisInDomainResult
{
  public AnalysisInDomainResult();
  public Metadata Metadata { get; set; }
  public Guid RequestId { get; set; }
  public object Result { get; set; }
}

La propriété Result contient le résultat réel de la reconnaissance. Comme vous pouvez le voir, il est de type System.Object, ce qui signifie qu’il contient des données brutes. Plus spécifiquement, résultat stocke la réponse JSON renvoyée par le service de la Vision de l’ordinateur. En fonction du nombre de célébrités détecté, ce JSON peut être très complexe, et c’est pourquoi qu'il s’agit d’un objet au lieu d’un type plus spécialisé. Elle définit essentiellement d’un tableau d’éléments, chacun contenant le nom des célébrités, la taille du rectangle face et une valeur représentant la précision du résultat. Par exemple, si le résultat contient une célébrité, le JSON ressemble à ce qui suit (où CelebrityName représente le nom réel célébrités) :

{"celebrities": [
  {
    "name": "CelebrityName",
    "faceRectangle": {
      "left": 169,
      "top": 148,
      "width": 186,
      "height": 186
    },
    "confidence": 0.9064959
  }
]}

Si le JSON contient plusieurs célébrités, vous pouvez l’imaginer complexité possible. Par conséquent, des principaux problèmes à résoudre ici récupère nom célébrités à partir d’un type d’objet. Pour cela, à l’aide de la bibliothèque Newtonsoft.Json populaires, qui est une dépendance de la bibliothèque Microsoft.ProjectOxford.Vision et, par conséquent, est déjà disponible dans le projet PCL. La bibliothèque fournit un objet appelé JObject, à partir de l’espace de noms Netwonsoft.Json.Linq, ce qui permet l’analyse de balisage JSON stocké à l’intérieur d’un System.Object, avec une méthode appelée analyse. Vous pouvez traiter le résultat sous forme de chaîne JSON et récupérer l’élément souhaité, avec un index. La méthode suivante montre comment extraire un nom célébrités le résultat de l’analyse :

private string ParseCelebrityName(object analysisResult)
{
  JObject parsedJSONresult = JObject.Parse(analysisResult.ToString());
  var celebrities = from celebrity in parsedJSONresult["celebrities"]
                    select (string)celebrity["name"];
  return celebrities.FirstOrDefault();
}

Dans ce cas, je suppose qu'une image contient des seul célébrités, le code appelle FirstOrDefault sur le résultat de la requête LINQ, mais vous pouvez travailler avec le résultat de la requête pour voir combien de célébrités ont été détectées. L’étape suivante est déclarer et instancier la classe VisionServiceClient, à nouveau avec la clé secrète :

private readonly VisionServiceClient visionClient;
public CelebrityRecognitionPage()
{
  InitializeComponent();
  this.visionClient = new VisionServiceClient("YOUR-KEY-GOES-HERE");
}

À ce stade, vous pouvez ajouter le Gestionnaire d’événements-deux pour l’événement Clicked de boutons. Vous pouvez toujours réutiliser le code dans Figure 6, il vous suffit en remplaçant la ligne suivante :

this.BindingContext = analysisResult;

avec la ligne suivante :

this.CelebrityName.Text = ParseCelebrityName(analysisResult.Result);

Vous pouvez maintenant tester l’application en sélectionnant une image de votre favorite célébrités et voir comment les API de Vision ordinateur renvoient le résultat exact.

Pour résumer

Les API de Vision ordinateur ouvre un nombre incroyable de nouvelles opportunités, et ils fournissent un moyen simple pour décrire le monde, à l’aide de votre application sur n’importe quelle plateforme et sur n’importe quel appareil. Lors de la conférence Build 2016, Microsoft présenté le projet AI voir, en fonction de plusieurs Services Cognitive, y compris Computer Vision, qui est présentée dans une courte vidéo qui vous donne une perception réaliste de ce que vous pouvez faire. Regarder la vidéo à bit.ly/1qk5ZkJ.


Alessandro Del Sole est MVP Microsoft depuis 2008.  Promu MVP de l’année cinq fois, il est l’auteur de nombreux livres, livres, des vidéos et articles sur le développement .NET avec Visual Studio. DEL unique est considéré comme international un expert de Visual Studio, l’autorité de Windows Presentation Foundation et Visual Basic, plus il travaille comme un expert de développeur de solutions pour cerveau-Sys (www.brain-sys.it), la mise au point sur le développement .NET, formation et de Conseil. Vous pouvez le suivre sur Twitter : @progalex.

Merci à l'expert technique Microsoft suivant d'avoir relu cet article : James McCaffrey
Dr. James McCaffrey travaille pour Microsoft Research à Redmond, Wash. Il a travaillé sur plusieurs produits Microsoft, y compris Internet Explorer et Bing. Dr. James McCaffrey peut être atteint à jammc@microsoft.com.