Reconnaître les traits Windows Ink en tant que texte et formes

Convertissez les traits d’encre en texte et en formes en utilisant les capacités de reconnaissance intégrées à Windows Ink.

API importantes : InkCanvas, Windows.UI.Input.Inking

Reconnaissance de forme libre avec analyse d’entrée manuscrite

Ici, nous montrons comment utiliser le moteur d’analyse Windows Ink (Windows.UI.Input.Inking.Analysis) pour classifier, analyser et reconnaître un ensemble de traits de forme libre sur un InkCanvas en tant que texte ou forme. (En plus de la reconnaissance de texte et de forme, l’analyse manuscrite peut également être utilisée pour reconnaître la structure du document, les listes à puces et les dessins génériques.)

Remarque

Pour connaître les scénarios de texte brut simples de base, tels que l’entrée de formulaire, reportez-vous à Reconnaissance de l’écriture manuscrite sous contrainte plus loin dans cette rubrique.

Dans cet exemple, la reconnaissance est déclenchée lorsque l’utilisateur clique sur un bouton pour indiquer qu’il a fini de dessiner.

Télécharger cet exemple à partir de l’exemple d’analyse d’entrée manuscrite (de base)

  1. Nous commençons par configurer l’interface utilisateur (MainPage.xaml).

    L’interface utilisateur inclut un bouton « Reconnaître », un InkCanvas et un espace standard. Lorsque vous appuyez sur le bouton « Reconnaître », tous les traits d’encre de l’espace d’encre sont analysés et (s’ils sont reconnus) les formes et le texte correspondants sont dessinés sur l’espace standard. Les traits d’encre originaux sont ensuite effacés de l’espace d’encre.

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="*"/>
         </Grid.RowDefinitions>
         <StackPanel x:Name="HeaderPanel" 
                     Orientation="Horizontal" 
                     Grid.Row="0">
             <TextBlock x:Name="Header" 
                         Text="Basic ink analysis sample" 
                         Style="{ThemeResource HeaderTextBlockStyle}" 
                         Margin="10,0,0,0" />
             <Button x:Name="recognize" 
                     Content="Recognize" 
                     Margin="50,0,10,0"/>
         </StackPanel>
         <Grid x:Name="drawingCanvas" Grid.Row="1">
    
             <!-- The canvas where we render the replacement text and shapes. -->
             <Canvas x:Name="recognitionCanvas" />
             <!-- The canvas for ink input. -->
             <InkCanvas x:Name="inkCanvas" />
    
         </Grid>
    </Grid>
    
  2. Dans le fichier code-behind de l’interface utilisateur (MainPage.xaml.cs), ajoutez les références de type d’espace de noms nécessaires à notre fonctionnalité d’analyse de l’encre et de l’encre :

  3. Nous spécifions ensuite nos variables globales :

     InkAnalyzer inkAnalyzer = new InkAnalyzer();
     IReadOnlyList<InkStroke> inkStrokes = null;
     InkAnalysisResult inkAnalysisResults = null;
    
  4. Ensuite, nous définissons quelques comportements de base en matière de saisie à l’encre :

    • InkPresenter est configuré de manière à interpréter les données d’entrée provenant du stylo, de la souris et du toucher comme des traits d’encre (InputDeviceTypes).
    • Les traits d’encre sont rendus sur InkCanvas en utilisant les InkDrawingAttributes spécifiés.
    • Un récepteur pour l’événement de clic sur le bouton « Reconnaître » est également déclaré.
    /// <summary>
    /// Initialize the UI page.
    /// </summary>
    public MainPage()
    {
        this.InitializeComponent();
    
        // Set supported inking device types.
        inkCanvas.InkPresenter.InputDeviceTypes =
            Windows.UI.Core.CoreInputDeviceTypes.Mouse |
            Windows.UI.Core.CoreInputDeviceTypes.Pen | 
            Windows.UI.Core.CoreInputDeviceTypes.Touch;
    
        // Set initial ink stroke attributes.
        InkDrawingAttributes drawingAttributes = new InkDrawingAttributes();
        drawingAttributes.Color = Windows.UI.Colors.Black;
        drawingAttributes.IgnorePressure = false;
        drawingAttributes.FitToCurve = true;
        inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes);
    
        // Listen for button click to initiate recognition.
        recognize.Click += RecognizeStrokes_Click;
    }
    
  5. Dans cet exemple, nous effectuons l’analyse de l’encre dans le gestionnaire d’événement de clic du bouton « Reconnaître ».

    • Tout d’abord, appelez GetStrokes sur le StrokeContainer du InkCanvas.InkPresenter pour obtenir la collection de tous les traits d’encre actuels.
    • Si des traits d’encre sont présents, passez-les en communication AddDataForStrokes dans InkAnalyzer.
    • Nous essayons de reconnaître à la fois les dessins et le texte, mais vous pouvez utiliser la méthode SetStrokeDataKind pour spécifier si vous êtes intéressé uniquement par le texte (y compris la structure de documents et les listes à puces) ou uniquement dans les dessins (y compris la reconnaissance de forme).
    • Appelez AnalyzeAsync pour lancer l’analyse de l’encre et obtenir InkAnalysisResult.
    • Si État renvoie un état de mise à jour, appelez FindNodes pour InkAnalysisNodeKind.InkWord et InkAnalysisNodeKind.InkDrawing.
    • Effectuez une itération dans les deux ensembles de types de nœuds et dessinez le texte ou la forme correspondante sur l’espace de reconnaissance (sous l’espace d’encre).
    • Enfin, supprimez les nœuds reconnus de l’analyseur d’encre et les traits d’encre correspondants de l’espace d’encre.
    /// <summary>
    /// The "Analyze" button click handler.
    /// Ink recognition is performed here.
    /// </summary>
    /// <param name="sender">Source of the click event</param>
    /// <param name="e">Event args for the button click routed event</param>
    private async void RecognizeStrokes_Click(object sender, RoutedEventArgs e)
    {
        inkStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
        // Ensure an ink stroke is present.
        if (inkStrokes.Count > 0)
        {
            inkAnalyzer.AddDataForStrokes(inkStrokes);
    
            // In this example, we try to recognizing both 
            // writing and drawing, so the platform default 
            // of "InkAnalysisStrokeKind.Auto" is used.
            // If you're only interested in a specific type of recognition,
            // such as writing or drawing, you can constrain recognition 
            // using the SetStrokDataKind method as follows:
            // foreach (var stroke in strokesText)
            // {
            //     analyzerText.SetStrokeDataKind(
            //      stroke.Id, InkAnalysisStrokeKind.Writing);
            // }
            // This can improve both efficiency and recognition results.
            inkAnalysisResults = await inkAnalyzer.AnalyzeAsync();
    
            // Have ink strokes on the canvas changed?
            if (inkAnalysisResults.Status == InkAnalysisStatus.Updated)
            {
                // Find all strokes that are recognized as handwriting and 
                // create a corresponding ink analysis InkWord node.
                var inkwordNodes = 
                    inkAnalyzer.AnalysisRoot.FindNodes(
                        InkAnalysisNodeKind.InkWord);
    
                // Iterate through each InkWord node.
                // Draw primary recognized text on recognitionCanvas 
                // (for this example, we ignore alternatives), and delete 
                // ink analysis data and recognized strokes.
                foreach (InkAnalysisInkWord node in inkwordNodes)
                {
                    // Draw a TextBlock object on the recognitionCanvas.
                    DrawText(node.RecognizedText, node.BoundingRect);
    
                    foreach (var strokeId in node.GetStrokeIds())
                    {
                        var stroke = 
                            inkCanvas.InkPresenter.StrokeContainer.GetStrokeById(strokeId);
                        stroke.Selected = true;
                    }
                    inkAnalyzer.RemoveDataForStrokes(node.GetStrokeIds());
                }
                inkCanvas.InkPresenter.StrokeContainer.DeleteSelected();
    
                // Find all strokes that are recognized as a drawing and 
                // create a corresponding ink analysis InkDrawing node.
                var inkdrawingNodes =
                    inkAnalyzer.AnalysisRoot.FindNodes(
                        InkAnalysisNodeKind.InkDrawing);
                // Iterate through each InkDrawing node.
                // Draw recognized shapes on recognitionCanvas and
                // delete ink analysis data and recognized strokes.
                foreach (InkAnalysisInkDrawing node in inkdrawingNodes)
                {
                    if (node.DrawingKind == InkAnalysisDrawingKind.Drawing)
                    {
                        // Catch and process unsupported shapes (lines and so on) here.
                    }
                    // Process generalized shapes here (ellipses and polygons).
                    else
                    {
                        // Draw an Ellipse object on the recognitionCanvas (circle is a specialized ellipse).
                        if (node.DrawingKind == InkAnalysisDrawingKind.Circle || node.DrawingKind == InkAnalysisDrawingKind.Ellipse)
                        {
                            DrawEllipse(node);
                        }
                        // Draw a Polygon object on the recognitionCanvas.
                        else
                        {
                            DrawPolygon(node);
                        }
                        foreach (var strokeId in node.GetStrokeIds())
                        {
                            var stroke = inkCanvas.InkPresenter.StrokeContainer.GetStrokeById(strokeId);
                            stroke.Selected = true;
                        }
                    }
                    inkAnalyzer.RemoveDataForStrokes(node.GetStrokeIds());
                }
                inkCanvas.InkPresenter.StrokeContainer.DeleteSelected();
            }
        }
    }
    
  6. Voici la fonction permettant de dessiner un TextBlock dans notre espace de reconnaissance. Nous utilisons le niveau du bit du trait d’encre associé sur l’espace d’encre pour définir la position et la taille de police du TextBlock.

     /// <summary>
     /// Draw ink recognition text string on the recognitionCanvas.
     /// </summary>
     /// <param name="recognizedText">The string returned by text recognition.</param>
     /// <param name="boundingRect">The bounding rect of the original ink writing.</param>
     private void DrawText(string recognizedText, Rect boundingRect)
     {
         TextBlock text = new TextBlock();
         Canvas.SetTop(text, boundingRect.Top);
         Canvas.SetLeft(text, boundingRect.Left);
    
         text.Text = recognizedText;
         text.FontSize = boundingRect.Height;
    
         recognitionCanvas.Children.Add(text);
     }
    
  7. Voici les fonctions permettant de dessiner des ellipses et des polygones sur notre espace de reconnaissance. Nous utilisons le niveau du bit du trait d’encre associé sur l’espace d’encre pour définir la position et la taille de police des formes.

     // Draw an ellipse on the recognitionCanvas.
     private void DrawEllipse(InkAnalysisInkDrawing shape)
     {
         var points = shape.Points;
         Ellipse ellipse = new Ellipse();
    
         ellipse.Width = shape.BoundingRect.Width;
         ellipse.Height = shape.BoundingRect.Height;
    
         Canvas.SetTop(ellipse, shape.BoundingRect.Top);
         Canvas.SetLeft(ellipse, shape.BoundingRect.Left);
    
         var brush = new SolidColorBrush(Windows.UI.ColorHelper.FromArgb(255, 0, 0, 255));
         ellipse.Stroke = brush;
         ellipse.StrokeThickness = 2;
         recognitionCanvas.Children.Add(ellipse);
     }
    
     // Draw a polygon on the recognitionCanvas.
     private void DrawPolygon(InkAnalysisInkDrawing shape)
     {
         List<Point> points = new List<Point>(shape.Points);
         Polygon polygon = new Polygon();
    
         foreach (Point point in points)
         {
             polygon.Points.Add(point);
         }
    
         var brush = new SolidColorBrush(Windows.UI.ColorHelper.FromArgb(255, 0, 0, 255));
         polygon.Stroke = brush;
         polygon.StrokeThickness = 2;
         recognitionCanvas.Children.Add(polygon);
     }
    

Voici cet exemple en action :

Avant l’analyse Après analyse
Before analysis After analysis

Reconnaissance de l’écriture manuscrite contrainte

Dans la section précédente (reconnaissance de forme libre avec analyse d’encre), nous avons montré comment utiliser les API d’analyse d’encre pour analyser et reconnaître des traits d’encre arbitraires dans une zone InkCanvas.

Dans cette section, nous montrons comment utiliser le moteur de reconnaissance de l’écriture manuscrite Windows Ink (et non l’analyse manuscrite) pour convertir un ensemble de traits sur InkCanvas en texte (en fonction du module linguistique par défaut installé).

Remarque

La reconnaissance de l’écriture manuscrite de base présentée dans cette section convient le mieux aux scénarios d’entrée de texte à ligne unique, tels que l’entrée de formulaire. Pour obtenir des scénarios de reconnaissance plus riches qui incluent l’analyse et l’interprétation de la structure du document, des éléments de liste, des formes et des dessins (en plus de la reconnaissance de texte), reportez-vous à la section précédente : Reconnaissance de forme libre avec analyse manuscrite.

Dans cet exemple, la reconnaissance est déclenchée lorsque l’utilisateur clique sur un bouton pour indiquer qu’il a fini de rédiger.

Télécharger cet exemple à partir de l’exemple de reconnaissance de l’écriture manuscrite à l’encre

  1. Tout d’abord, nous avons configuré l’interface utilisateur.

    L’interface utilisateur comporte un bouton « Reconnaître », InkCanvaset une zone pour afficher les résultats de la reconnaissance.

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="*"/>
         </Grid.RowDefinitions>
         <StackPanel x:Name="HeaderPanel"
                     Orientation="Horizontal"
                     Grid.Row="0">
                 <TextBlock x:Name="Header"
                     Text="Basic ink recognition sample"
                     Style="{ThemeResource HeaderTextBlockStyle}"
                     Margin="10,0,0,0" />
                 <Button x:Name="recognize"
                     Content="Recognize"
                     Margin="50,0,10,0"/>
         </StackPanel>
         <Grid Grid.Row="1">
             <Grid.RowDefinitions>
                 <RowDefinition Height="*"/>
                 <RowDefinition Height="Auto"/>
             </Grid.RowDefinitions>
             <InkCanvas x:Name="inkCanvas"
                 Grid.Row="0"/>
             <TextBlock x:Name="recognitionResult"
                 Grid.Row="1"
                 Margin="50,0,10,0"/>
         </Grid>
     </Grid>
    
  2. Pour cet exemple, vous devez d’abord ajouter les références de type d’espace de noms requises pour nos fonctionnalités d’entrée manuscrite :

  3. Ensuite, nous définissons quelques comportements de base en matière de saisie à l’encre.

    InkPresenter est configuré de manière à interpréter les données d’entrée provenant du stylo et de la souris comme des traits d’encre (InputDeviceTypes). Les traits d’encre sont rendus sur InkCanvas en utilisant les InkDrawingAttributes spécifiés. Un récepteur pour l’événement de clic sur le bouton « Reconnaître » est également déclaré.

    public MainPage()
        {
            this.InitializeComponent();
    
            // Set supported inking device types.
            inkCanvas.InkPresenter.InputDeviceTypes =
                Windows.UI.Core.CoreInputDeviceTypes.Mouse |
                Windows.UI.Core.CoreInputDeviceTypes.Pen;
    
            // Set initial ink stroke attributes.
            InkDrawingAttributes drawingAttributes = new InkDrawingAttributes();
            drawingAttributes.Color = Windows.UI.Colors.Black;
            drawingAttributes.IgnorePressure = false;
            drawingAttributes.FitToCurve = true;
            inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes);
    
            // Listen for button click to initiate recognition.
            recognize.Click += Recognize_Click;
        }
    
  4. Enfin, nous effectuons la reconnaissance de l’écriture manuscrite de base. Dans cet exemple, nous utilisons le gestionnaire d’événement de clic du bouton « Reconnaître » pour effectuer la reconnaissance de l’écriture manuscrite.

    // Get all strokes on the InkCanvas.
        IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
    
    • Un InkRecognizerContainer est créé pour gérer le processus de reconnaissance de l’écriture manuscrite.
    // Create a manager for the InkRecognizer object
        // used in handwriting recognition.
        InkRecognizerContainer inkRecognizerContainer =
            new InkRecognizerContainer();
    
    // Recognize all ink strokes on the ink canvas.
        IReadOnlyList<InkRecognitionResult> recognitionResults =
            await inkRecognizerContainer.RecognizeAsync(
                inkCanvas.InkPresenter.StrokeContainer,
                InkRecognitionTarget.All);
    
    • Chaque objet InkRecognitionResult contient un ensemble de candidats de texte. L’élément le plus élevé de cette liste est considéré par le moteur de reconnaissance comme la meilleure correspondance, suivi des autres candidats par ordre de confiance décroissante.

      Nous parcourons chaque InkRecognitionResult et compilons la liste des candidats. Les candidats sont alors affichés et InkStrokeContainer est effacé (ce qui efface également InkCanvas).

    string str = "Recognition result\n";
        // Iterate through the recognition results.
        foreach (var result in recognitionResults)
        {
            // Get all recognition candidates from each recognition result.
            IReadOnlyList<string> candidates = result.GetTextCandidates();
            str += "Candidates: " + candidates.Count.ToString() + "\n";
            foreach (string candidate in candidates)
            {
                str += candidate + " ";
            }
        }
        // Display the recognition candidates.
        recognitionResult.Text = str;
        // Clear the ink canvas once recognition is complete.
        inkCanvas.InkPresenter.StrokeContainer.Clear();
    
    • Voici l’exemple complet du gestionnaire de clics.
    // Handle button click to initiate recognition.
        private async void Recognize_Click(object sender, RoutedEventArgs e)
        {
            // Get all strokes on the InkCanvas.
            IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
    
            // Ensure an ink stroke is present.
            if (currentStrokes.Count > 0)
            {
                // Create a manager for the InkRecognizer object
                // used in handwriting recognition.
                InkRecognizerContainer inkRecognizerContainer =
                    new InkRecognizerContainer();
    
                // inkRecognizerContainer is null if a recognition engine is not available.
                if (!(inkRecognizerContainer == null))
                {
                    // Recognize all ink strokes on the ink canvas.
                    IReadOnlyList<InkRecognitionResult> recognitionResults =
                        await inkRecognizerContainer.RecognizeAsync(
                            inkCanvas.InkPresenter.StrokeContainer,
                            InkRecognitionTarget.All);
                    // Process and display the recognition results.
                    if (recognitionResults.Count > 0)
                    {
                        string str = "Recognition result\n";
                        // Iterate through the recognition results.
                        foreach (var result in recognitionResults)
                        {
                            // Get all recognition candidates from each recognition result.
                            IReadOnlyList<string> candidates = result.GetTextCandidates();
                            str += "Candidates: " + candidates.Count.ToString() + "\n";
                            foreach (string candidate in candidates)
                            {
                                str += candidate + " ";
                            }
                        }
                        // Display the recognition candidates.
                        recognitionResult.Text = str;
                        // Clear the ink canvas once recognition is complete.
                        inkCanvas.InkPresenter.StrokeContainer.Clear();
                    }
                    else
                    {
                        recognitionResult.Text = "No recognition results.";
                    }
                }
                else
                {
                    Windows.UI.Popups.MessageDialog messageDialog = new Windows.UI.Popups.MessageDialog("You must install handwriting recognition engine.");
                    await messageDialog.ShowAsync();
                }
            }
            else
            {
                recognitionResult.Text = "No ink strokes to recognize.";
            }
        }
    

Reconnaissance internationale

La reconnaissance de l’écriture manuscrite intégrée à la plateforme Windows Ink comprend un vaste sous-ensemble de langues et de lieux pris en charge par Windows.

Reportez-vous à la rubrique de la propriété InkRecognizer.Name pour une liste des langues prises en charge par InkRecognizer.

Votre application peut interroger l’ensemble des moteurs de reconnaissance de l’écriture manuscrite installés et utiliser l’un d’entre eux, ou laisser l’utilisateur sélectionner la langue par défaut.

Notez que les utilisateurs peuvent consulter la liste des langues installées en allant dans Paramètres -> Heure et langue. Les langues installées sont répertoriées sous Langues.

Pour installer de nouveaux modules linguistiques et activer la reconnaissance de l’écriture manuscrite pour cette langue :

  1. Allez dans Paramètres > Heure et langue > Région et langue.
  2. Sélectionnez Ajouter une langue.
  3. Sélectionnez une langue dans la liste, puis choisissez la région. La langue est désormais répertoriée dans la page Région et langue.
  4. Cliquez sur la langue et sélectionnez Options.
  5. Sur la page Options de langue, téléchargez le moteur de reconnaissance de l’écriture manuscrite (ils peuvent également télécharger le module linguistique complet, le moteur de reconnaissance vocale et la disposition du clavier ici).

Nous montrons ici comment utiliser le moteur de reconnaissance de l’écriture manuscrite pour interpréter un ensemble de traits sur un InkCanvas en fonction du module de reconnaissance sélectionné.

La reconnaissance est déclenchée par l’utilisateur qui clique sur un bouton lorsqu’il a fini d’écrire.

  1. Tout d’abord, nous avons configuré l’interface utilisateur.

    L’interface utilisateur comprend un bouton « Reconnaître », une liste déroulante qui répertorie tous les modules de reconnaissance de l’écriture manuscrite installés, InkCanvas et une zone d’affichage des résultats de la reconnaissance.

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <StackPanel x:Name="HeaderPanel"
                        Orientation="Horizontal"
                        Grid.Row="0">
                <TextBlock x:Name="Header"
                           Text="Advanced international ink recognition sample"
                           Style="{ThemeResource HeaderTextBlockStyle}"
                           Margin="10,0,0,0" />
                <ComboBox x:Name="comboInstalledRecognizers"
                         Margin="50,0,10,0">
                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding Name}" />
                            </StackPanel>
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>
                <Button x:Name="buttonRecognize"
                        Content="Recognize"
                        IsEnabled="False"
                        Margin="50,0,10,0"/>
            </StackPanel>
            <Grid Grid.Row="1">
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <InkCanvas x:Name="inkCanvas"
                           Grid.Row="0"/>
                <TextBlock x:Name="recognitionResult"
                           Grid.Row="1"
                           Margin="50,0,10,0"/>
            </Grid>
        </Grid>
    
  2. Ensuite, nous définissons quelques comportements de base en matière de saisie à l’encre.

    InkPresenter est configuré de manière à interpréter les données d’entrée provenant du stylo et de la souris comme des traits d’encre (InputDeviceTypes). Les traits d’encre sont rendus sur InkCanvas en utilisant les InkDrawingAttributes spécifiés.

    Nous appelons une fonction InitializeRecognizerList pour remplir la zone de liste modifiable du module de reconnaissance avec une liste de systèmes de reconnaissance de l’écriture manuscrite installés.

    Nous déclarons également des récepteurs pour l’événement de clic sur le bouton « Reconnaître » et l’événement de modification de la sélection sur la zone de liste modifiable du module de reconnaissance.

     public MainPage()
     {
        this.InitializeComponent();
    
        // Set supported inking device types.
        inkCanvas.InkPresenter.InputDeviceTypes =
            Windows.UI.Core.CoreInputDeviceTypes.Mouse |
            Windows.UI.Core.CoreInputDeviceTypes.Pen;
    
        // Set initial ink stroke attributes.
        InkDrawingAttributes drawingAttributes = new InkDrawingAttributes();
        drawingAttributes.Color = Windows.UI.Colors.Black;
        drawingAttributes.IgnorePressure = false;
        drawingAttributes.FitToCurve = true;
        inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes);
    
        // Populate the recognizer combo box with installed recognizers.
        InitializeRecognizerList();
    
        // Listen for combo box selection.
        comboInstalledRecognizers.SelectionChanged +=
            comboInstalledRecognizers_SelectionChanged;
    
        // Listen for button click to initiate recognition.
        buttonRecognize.Click += Recognize_Click;
    }
    
  3. Nous remplissons la zone de liste modifiable du module de reconnaissance avec une liste de systèmes de reconnaissance de l’écriture manuscrite installés.

    Un InkRecognizerContainer est créé pour gérer le processus de reconnaissance de l’écriture manuscrite. Utilisez cet objet pour appeler GetRecognizers et récupérer la liste des modules de reconnaissance installés pour remplir la zone de liste modifiable du module de reconnaissance.

    // Populate the recognizer combo box with installed recognizers.
    private void InitializeRecognizerList()
    {
        // Create a manager for the handwriting recognition process.
        inkRecognizerContainer = new InkRecognizerContainer();
        // Retrieve the collection of installed handwriting recognizers.
        IReadOnlyList<InkRecognizer> installedRecognizers =
            inkRecognizerContainer.GetRecognizers();
        // inkRecognizerContainer is null if a recognition engine is not available.
        if (!(inkRecognizerContainer == null))
        {
            comboInstalledRecognizers.ItemsSource = installedRecognizers;
            buttonRecognize.IsEnabled = true;
        }
    }
    
  4. Mettez à jour le module de reconnaissance de l’écriture manuscrite si la sélection de la zone de liste modifiable du module de reconnaissance change.

    Utilisez InkRecognizerContainer pour appeler SetDefaultRecognizer en fonction du module de reconnaissance sélectionné de la zone de liste modifiable du module de reconnaissance.

    // Handle recognizer change.
        private void comboInstalledRecognizers_SelectionChanged(
            object sender, SelectionChangedEventArgs e)
        {
            inkRecognizerContainer.SetDefaultRecognizer(
                (InkRecognizer)comboInstalledRecognizers.SelectedItem);
        }
    
  5. Enfin, nous procédons à la reconnaissance de l’écriture manuscrite en nous basant sur le module de reconnaissance sélectionné. Dans cet exemple, nous utilisons le gestionnaire d’événement de clic du bouton « Reconnaître » pour effectuer la reconnaissance de l’écriture manuscrite.

    // Get all strokes on the InkCanvas.
        IReadOnlyList<InkStroke> currentStrokes =
            inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
    
    // Recognize all ink strokes on the ink canvas.
    IReadOnlyList<InkRecognitionResult> recognitionResults =
        await inkRecognizerContainer.RecognizeAsync(
            inkCanvas.InkPresenter.StrokeContainer,
            InkRecognitionTarget.All);
    
    • Chaque objet InkRecognitionResult contient un ensemble de candidats de texte. L’élément le plus élevé de cette liste est considéré par le moteur de reconnaissance comme la meilleure correspondance, suivi des autres candidats par ordre de confiance décroissante.

      Nous parcourons chaque InkRecognitionResult et compilons la liste des candidats. Les candidats sont alors affichés et InkStrokeContainer est effacé (ce qui efface également InkCanvas).

    string str = "Recognition result\n";
    // Iterate through the recognition results.
    foreach (InkRecognitionResult result in recognitionResults)
    {
            // Get all recognition candidates from each recognition result.
            IReadOnlyList<string> candidates =
                result.GetTextCandidates();
            str += "Candidates: " + candidates.Count.ToString() + "\n";
            foreach (string candidate in candidates)
            {
                str += candidate + " ";
            }
    }
    // Display the recognition candidates.
    recognitionResult.Text = str;
    // Clear the ink canvas once recognition is complete.
    inkCanvas.InkPresenter.StrokeContainer.Clear();
    
    • Voici l’exemple complet du gestionnaire de clics.
    // Handle button click to initiate recognition.
    private async void Recognize_Click(object sender, RoutedEventArgs e)
    {
        // Get all strokes on the InkCanvas.
        IReadOnlyList<InkStroke> currentStrokes =
            inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
    
        // Ensure an ink stroke is present.
        if (currentStrokes.Count > 0)
        {
            // inkRecognizerContainer is null if a recognition engine is not available.
            if (!(inkRecognizerContainer == null))
            {
                // Recognize all ink strokes on the ink canvas.
                IReadOnlyList<InkRecognitionResult> recognitionResults =
                    await inkRecognizerContainer.RecognizeAsync(
                        inkCanvas.InkPresenter.StrokeContainer,
                        InkRecognitionTarget.All);
                // Process and display the recognition results.
                if (recognitionResults.Count > 0)
                {
                    string str = "Recognition result\n";
                    // Iterate through the recognition results.
                    foreach (InkRecognitionResult result in recognitionResults)
                    {
                        // Get all recognition candidates from each recognition result.
                        IReadOnlyList<string> candidates =
                            result.GetTextCandidates();
                        str += "Candidates: " + candidates.Count.ToString() + "\n";
                        foreach (string candidate in candidates)
                        {
                            str += candidate + " ";
                        }
                    }
                    // Display the recognition candidates.
                    recognitionResult.Text = str;
                    // Clear the ink canvas once recognition is complete.
                    inkCanvas.InkPresenter.StrokeContainer.Clear();
                }
                else
                {
                    recognitionResult.Text = "No recognition results.";
                }
            }
            else
            {
                Windows.UI.Popups.MessageDialog messageDialog =
                    new Windows.UI.Popups.MessageDialog(
                        "You must install handwriting recognition engine.");
                await messageDialog.ShowAsync();
            }
        }
        else
        {
            recognitionResult.Text = "No ink strokes to recognize.";
        }
    }
    

Reconnaissance dynamique

Bien que les deux exemples précédents exigent que l’utilisateur appuie sur un bouton pour démarrer la reconnaissance, vous pouvez également effectuer une reconnaissance dynamique à l’aide d’une entrée de trait jumelée à une fonction de minutage de base.

Pour cet exemple, nous allons utiliser les mêmes paramètres d’interface utilisateur et de trait que l’exemple de reconnaissance internationale précédent.

  1. Ces objets globaux (InkAnalyzer, InkStroke, InkAnalysisResult, DispatcherTimer) sont utilisés dans toute notre application.

    // Stroke recognition globals.
    InkAnalyzer inkAnalyzer;
    DispatcherTimer recoTimer;
    
  2. Au lieu d’un bouton pour lancer la reconnaissance, nous ajoutons des récepteurs pour deux événements liés aux traits InkPresenter (StrokesCollected et StrokeStarted), et nous configurons un minuteur de base (DispatcherTimer) avec un intervalle d’une seconde entre les cycles.

    public MainPage()
    {
        this.InitializeComponent();
    
        // Set supported inking device types.
        inkCanvas.InkPresenter.InputDeviceTypes =
            Windows.UI.Core.CoreInputDeviceTypes.Mouse |
            Windows.UI.Core.CoreInputDeviceTypes.Pen;
    
        // Listen for stroke events on the InkPresenter to 
        // enable dynamic recognition.
        // StrokesCollected is fired when the user stops inking by 
        // lifting their pen or finger, or releasing the mouse button.
        inkCanvas.InkPresenter.StrokesCollected += inkCanvas_StrokesCollected;
        // StrokeStarted is fired when ink input is first detected.
        inkCanvas.InkPresenter.StrokeInput.StrokeStarted +=
            inkCanvas_StrokeStarted;
    
        inkAnalyzer = new InkAnalyzer();
    
        // Timer to manage dynamic recognition.
        recoTimer = new DispatcherTimer();
        recoTimer.Interval = TimeSpan.FromSeconds(1);
        recoTimer.Tick += recoTimer_TickAsync;
    }
    
  3. Nous définissons ensuite les gestionnaires des événements InkPresenter que nous avons déclarés à la première étape (nous substituons également l’événement de la page OnNavigatingFrom pour gérer notre minuterie).

    • StrokesCollected
      Ajoutez les traits d’encre (AddDataForStrokes) à l’analyseur d’encre et démarrez le minuteur de reconnaissance lorsque l’utilisateur arrête de produire des traits d’encre (en levant son stylo ou son doigt, ou en relâchant le bouton de la souris). Après une seconde d’absence de saisie d’encre, la reconnaissance est lancée.

      Utilisez la méthode SetStrokeDataKind pour spécifier si vous êtes intéressé uniquement par le texte (y compris la structure du document et les listes à puces) ou uniquement par les dessins (y compris la reconnaissance des formes).

    • StrokeStarted
      Si un nouveau trait commence avant le prochain cycle du minuteur, arrêtez le minuteur, car le nouveau trait est probablement la suite d’une seule entrée manuscrite.

    // Handler for the InkPresenter StrokeStarted event.
    // Don't perform analysis while a stroke is in progress.
    // If a new stroke starts before the next timer tick event,
    // stop the timer as the new stroke is likely the continuation
    // of a single handwriting entry.
    private void inkCanvas_StrokeStarted(InkStrokeInput sender, PointerEventArgs args)
    {
        recoTimer.Stop();
    }
    // Handler for the InkPresenter StrokesCollected event.
    // Stop the timer and add the collected strokes to the InkAnalyzer.
    // Start the recognition timer when the user stops inking (by 
    // lifting their pen or finger, or releasing the mouse button).
    // If ink input is not detected after one second, initiate recognition.
    private void inkCanvas_StrokesCollected(InkPresenter sender, InkStrokesCollectedEventArgs args)
    {
        recoTimer.Stop();
        // If you're only interested in a specific type of recognition,
        // such as writing or drawing, you can constrain recognition 
        // using the SetStrokDataKind method, which can improve both 
        // efficiency and recognition results.
        // In this example, "InkAnalysisStrokeKind.Writing" is used.
        foreach (var stroke in args.Strokes)
        {
            inkAnalyzer.AddDataForStroke(stroke);
            inkAnalyzer.SetStrokeDataKind(stroke.Id, InkAnalysisStrokeKind.Writing);
        }
        recoTimer.Start();
    }
    // Override the Page OnNavigatingFrom event handler to 
    // stop our timer if user leaves page.
    protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
    {
        recoTimer.Stop();
    }
    
  4. Enfin, nous effectuons la reconnaissance de l’écriture manuscrite. Dans cet exemple, nous utilisons le gestionnaire d’événement de cycle d’un DispatcherTimer pour lancer la reconnaissance de l’écriture manuscrite.

    • Appelez AnalyzeAsync pour lancer l’analyse de l’encre et obtenir InkAnalysisResult.
    • Si État renvoie un état Mis à jour, appeler FindNodes pour les types de nœuds de InkAnalysisNodeKind.InkWord.
    • Parcourir les nœuds et afficher le texte reconnu.
    • Enfin, supprimez les nœuds reconnus de l’analyseur d’encre et les traits d’encre correspondants de l’espace d’encre.
    private async void recoTimer_TickAsync(object sender, object e)
    {
        recoTimer.Stop();
        if (!inkAnalyzer.IsAnalyzing)
        {
            InkAnalysisResult result = await inkAnalyzer.AnalyzeAsync();
    
            // Have ink strokes on the canvas changed?
            if (result.Status == InkAnalysisStatus.Updated)
            {
                // Find all strokes that are recognized as handwriting and 
                // create a corresponding ink analysis InkWord node.
                var inkwordNodes =
                    inkAnalyzer.AnalysisRoot.FindNodes(
                        InkAnalysisNodeKind.InkWord);
    
                // Iterate through each InkWord node.
                // Display the primary recognized text (for this example, 
                // we ignore alternatives), and then delete the 
                // ink analysis data and recognized strokes.
                foreach (InkAnalysisInkWord node in inkwordNodes)
                {
                    string recognizedText = node.RecognizedText;
                    // Display the recognition candidates.
                    recognitionResult.Text = recognizedText;
    
                    foreach (var strokeId in node.GetStrokeIds())
                    {
                        var stroke =
                            inkCanvas.InkPresenter.StrokeContainer.GetStrokeById(strokeId);
                        stroke.Selected = true;
                    }
                    inkAnalyzer.RemoveDataForStrokes(node.GetStrokeIds());
                }
                inkCanvas.InkPresenter.StrokeContainer.DeleteSelected();
            }
        }
        else
        {
            // Ink analyzer is busy. Wait a while and try again.
            recoTimer.Start();
        }
    }
    

Exemples de la rubrique

Autres exemples