Riconoscere i tratti di Windows Ink come testo e forme

Convertire i tratti input penna in testo e forme usando le funzionalità di riconoscimento in Windows Ink.

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

Riconoscimento in formato libero con analisi dell'input penna

Viene dimostrato come usare il motore di analisi di Windows Ink (Windows.UI.Input.Inking.Analysis) per classificare, analizzare e riconoscere un set di tratti in formato libero su un InkCanvas come testo o forme. Oltre al riconoscimento del testo e delle forme, l'analisi dell'input penna può essere usata per riconoscere la struttura del documento, elenchi puntati e disegni generici.

Nota

Per scenari in testo normale, a riga singola e di base come l'input del modulo, vedere Riconoscimento della grafia vincolata più avanti in questo argomento.

In questo esempio, il riconoscimento viene avviato quando l'utente fa clic su un pulsante per indicare che ha terminato il disegno.

Scaricare questo esempio dall'esempio di analisi dell'input penna (di base)

  1. Prima di tutto, si imposta l'interfaccia utente (MainPage.xaml).

    L'interfaccia utente include un pulsante "Riconosci", un InkCanvas e un Canvas standard. Quando si preme il pulsante "Riconosci", tutti i tratti input penna nell'area di disegno input penna vengono analizzati e (se riconosciuti) le forme e il testo corrispondenti vengono disegnati sull'area di disegno standard. I tratti input penna originali vengono quindi eliminati dall'area di disegno input penna.

    <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. Nel file code-behind dell'interfaccia utente (MainPage.xaml.cs) aggiungere i riferimenti ai tipi di spazio dei nomi necessari per la funzionalità di analisi input penna:

  3. Si specificano quindi le variabili globali:

     InkAnalyzer inkAnalyzer = new InkAnalyzer();
     IReadOnlyList<InkStroke> inkStrokes = null;
     InkAnalysisResult inkAnalysisResults = null;
    
  4. Ora si impostano alcuni comportamenti di input penna di base:

    • InkPresenter è configurato per interpretare i dati di input da penna, mouse e tocco come tratti di input penna (InputDeviceTypes).
    • I tratti di input penna vengono sottoposti a rendering su InkCanvas usando gli elementi InkDrawingAttributes specificati.
    • Si dichiara anche un listener per l'evento clic sul pulsante "Riconosci".
    /// <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. Per questo esempio, si esegue l'analisi dell'input penna nel gestore dell'evento clic del pulsante "Riconosci".

    • Innanzitutto, chiamare GetStrokes su StrokeContainer di InkCanvas.InkPresenter per ottenere la raccolta di tutti i tratti input penna correnti.
    • Se sono presenti tratti input penna, passarli in una chiamata a AddDataForStrokes di InkAnalyzer.
    • Si sta provando a riconoscere disegni e testo, ma è possibile usare il metodo SetStrokeDataKind per specificare se si è interessati solo al testo (inclusi struttura del documento ed elenchi puntati) o solo ai disegni (incluso il riconoscimento della forma).
    • Chiamare AnalyzeAsync per avviare l'analisi input penna e ottenere InkAnalysisResult.
    • Se Status restituisce uno stato Updated, chiamare FindNodes per InkAnalysisNodeKind.InkWord e InkAnalysisNodeKind.InkDrawing.
    • Scorrere entrambi i set di tipi di nodo e disegnare il testo o la forma rispettiva sull'area di disegno di riconoscimento (sotto l'area di disegno input penna).
    • Infine, eliminare i nodi riconosciuti da InkAnalyzer e i tratti input penna corrispondenti dall'area di disegno input penna.
    /// <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. Ecco la funzione per disegnare un elemento TextBlock sull'area di disegno di riconoscimento. Si usa il rettangolo di delimitazione del tratto input penna associato sull'area di disegno input penna per impostare la posizione e le dimensioni del carattere dell'elemento 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. Ecco le funzioni per disegnare ellissi e poligoni nell'area di disegno di riconoscimento. Si usa il rettangolo di delimitazione del tratto input penna associato sull'area di disegno input penna per impostare la posizione e le dimensioni del carattere delle forme.

     // 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);
     }
    

Ecco questo esempio in azione:

Prima dell'analisi Dopo l'analisi
Before analysis After analysis

Riconoscimento della grafia vincolato

La sezione precedente (Riconoscimento in formato libero con analisi input penna) ha mostrato come usare le API di analisi input penna per analizzare e riconoscere i tratti input penna arbitrari all'interno di un'area InkCanvas.

Questa sezione mostra come usare il motore di riconoscimento della grafia di Windows Ink (non l'analisi input penna) per convertire un set di tratti in un elemento InkCanvas in testo (in base al Language Pack predefinito installato).

Nota

Il riconoscimento della grafia di base illustrato in questa sezione è più adatto a scenari di input di testo a riga singola, ad esempio l'input del modulo. Per scenari di riconoscimento più complessi che includono l'analisi e l'interpretazione della struttura del documento, di elementi elenco, forme e disegni (oltre al riconoscimento del testo), vedere la sezione precedente: Riconoscimento in formato libero con l'analisi input penna.

In questo esempio, il riconoscimento viene avviato quando l'utente fa clic su un pulsante per indicare di aver terminato la scrittura.

Scaricare questo esempio dall'esempio di riconoscimento della grafia input penna

  1. Innanzitutto, si imposta l'interfaccia utente.

    L'interfaccia utente include un pulsante "Riconosci", l'elemento InkCanvas e un'area per visualizzare i risultati del riconoscimento.

    <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. Per questo esempio, è innanzitutto necessario aggiungere i riferimenti al tipo di spazio dei nomi necessari per la funzionalità input penna:

  3. Ora si impostano alcuni comportamenti di input penna di base:

    InkPresenter viene configurato per interpretare i dati di input da penna e mouse come tratti input penna (InputDeviceTypes). I tratti di input penna vengono sottoposti a rendering su InkCanvas usando gli elementi InkDrawingAttributes specificati. Si dichiara anche un listener per l'evento clic sul pulsante "Riconosci".

    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. Infine, si esegue il riconoscimento della grafia di base. Per questo esempio si usa il gestore dell'evento clic del pulsante "Riconosci" per eseguire il riconoscimento della grafia.

    // Get all strokes on the InkCanvas.
        IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
    
    // 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);
    
    • Ogni oggetto InkRecognitionResult contiene un set di candidati di testo. L'elemento più in alto in questo elenco è considerato dal motore di riconoscimento come la corrispondenza migliore, seguito dai candidati rimanenti in ordine decrescente di attendibilità.

      Si scorre ciascun elemento InkRecognitionResult e si compila la lista di candidati. I candidati vengono visualizzati e InkStrokeContainer viene cancellato (anche InkCanvas viene cancellato).

    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();
    
    • Ecco l'esempio di gestore clic in forma completa.
    // 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.";
            }
        }
    

Riconoscimento internazionale

Il riconoscimento della grafia integrato nella piattaforma WindowsInk include un sottoinsieme completo di impostazioni locali e lingue supportate da Windows.

Vedere l'argomento sulla proprietà InkRecognizer.Name per un elenco di lingue supportate da InkRecognizer.

L'app può eseguire una query sul set di motori di riconoscimento della grafia installati e usarli oppure consentire a un utente di selezionare la lingua preferita.

Nota Gli utenti possono visualizzare un elenco delle lingue installate andando a Impostazioni -> Ora & Lingua. Le lingue installate sono elencate in Lingue.

Per installare nuovi Language Pack e abilitare il riconoscimento della grafia per quella lingua:

  1. Andare a Impostazioni > Ora & lingua > Area & lingua.
  2. Selezionare Aggiungi una lingua.
  3. Selezionare una lingua dall'elenco, quindi scegliere la versione dell'area. La lingua è ora elencata nella pagina Area & lingua.
  4. Fare clic sulla lingua e selezionare Opzioni.
  5. Nella pagina Opzioni lingua scaricare il motore di riconoscimento della grafia (qui è anche possibile scaricare il Language Pack completo, il motore di riconoscimento vocale e il layout di tastiera).

Qui si dimostra come usare il motore di riconoscimento della grafia per interpretare un set di tratti su un elemento InkCanvas in base al riconoscimento selezionato.

Il riconoscimento viene avviato dall'utente facendo clic su un pulsante al termine della scrittura.

  1. Innanzitutto, si imposta l'interfaccia utente.

    L'interfaccia utente include un pulsante "Riconosci", una casella combinata che elenca tutti i riconoscimenti della grafia installati, l'elemento InkCanvas e un'area in cui visualizzare i risultati del riconoscimento.

    <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. Ora si impostano alcuni comportamenti di input penna di base:

    InkPresenter viene configurato per interpretare i dati di input da penna e mouse come tratti input penna (InputDeviceTypes). I tratti di input penna vengono sottoposti a rendering su InkCanvas usando gli elementi InkDrawingAttributes specificati.

    Si chiama una funzione InitializeRecognizerList per popolare la casella combinata del riconoscimento con un elenco di riconoscimenti della grafia installati.

    Si dichiarano anche listener per l'evento clic sul pulsante "Riconosci" e l'evento di modifica della selezione nella casella combinata del riconoscimento.

     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. Si popola la casella combinata del riconoscimento con un elenco di riconoscimenti della grafia installati.

    Si crea un InkRecognizerContainer per gestire il processo di riconoscimento della grafia. Usare questo oggetto per chiamare GetRecognizers e recuperare l'elenco dei riconoscimenti installati per popolare la casella combinata relativa.

    // 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. Aggiornare il riconoscimento della grafia se la selezione della casella combinata relativa cambia.

    Usare InkRecognizerContainer per chiamare SetDefaultRecognizer in base al riconoscimento selezionato dalla casella combinata relativa.

    // Handle recognizer change.
        private void comboInstalledRecognizers_SelectionChanged(
            object sender, SelectionChangedEventArgs e)
        {
            inkRecognizerContainer.SetDefaultRecognizer(
                (InkRecognizer)comboInstalledRecognizers.SelectedItem);
        }
    
  5. Infine, si esegue il riconoscimento della grafia in base al riconoscimento della grafia selezionato. Per questo esempio si usa il gestore dell'evento clic del pulsante "Riconosci" per eseguire il riconoscimento della grafia.

    // 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);
    
    • Ogni oggetto InkRecognitionResult contiene un set di candidati di testo. L'elemento più in alto in questo elenco è considerato dal motore di riconoscimento come la corrispondenza migliore, seguito dai candidati rimanenti in ordine decrescente di attendibilità.

      Si scorre ciascun elemento InkRecognitionResult e si compila la lista di candidati. I candidati vengono visualizzati e InkStrokeContainer viene cancellato (anche InkCanvas viene cancellato).

    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();
    
    • Ecco l'esempio di gestore clic in forma completa.
    // 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.";
        }
    }
    

Riconoscimento dinamico

Mentre i due esempi precedenti richiedono all'utente di premere un pulsante per avviare il riconoscimento, è possibile eseguire il riconoscimento dinamico usando l'input del tratto associato a una funzione di timing di base.

Per questo esempio si useranno le stesse impostazioni dell'interfaccia utente e del tratto dell'esempio di riconoscimento internazionale precedente.

  1. Questi oggetti globali (InkAnalyzer, InkStroke, InkAnalysisResult, DispatcherTimer) vengono usati nell'app.

    // Stroke recognition globals.
    InkAnalyzer inkAnalyzer;
    DispatcherTimer recoTimer;
    
  2. Anziché un pulsante per avviare il riconoscimento, si aggiungono listener per due eventi tratto InkPresenter (StrokesCollected e StrokeStarted), e si imposta un timer di base (DispatcherTimer) con un secondo intervallo Tick.

    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. Si definiscono i gestori per gli eventi InkPresenter dichiarati nel primo passaggio (si esegue anche l'override dell'evento pagina OnNavigatingFrom per gestire il timer).

    • StrokesCollected
      Aggiungere tratti input penna (AddDataForStrokes) a InkAnalyzer e si avvia il timer del riconoscimento quando l'utente interrompe l'input penna (sollevando la penna o il dito o rilasciando il pulsante del mouse). Dopo un secondo di nessun input penna, viene avviato il riconoscimento.

      Usare il metodo SetStrokeDataKind per specificare se si è interessati al testo (inclusi la struttura del documento e gli elenchi puntati) o solo ai disegni (incluso il riconoscimento della forma).

    • StrokeStarted
      Se un nuovo tratto inizia prima dell'evento tick del timer successivo, arrestare il timer perché il nuovo tratto è probabilmente la continuazione di un singolo elemento di grafia.

    // 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. Infine, si esegue il riconoscimento della grafia. Per questo esempio, si usa il gestore dell'evento Tick di un elemento DispatcherTimer per avviare il riconoscimento della grafia.

    • Chiamare AnalyzeAsync per avviare l'analisi input penna e ottenere InkAnalysisResult.
    • Se Status restituisce uno stato Updated, chiamare FindNodes per i tipi di nodo di InkAnalysisNodeKind.InkWord.
    • Scorrere i nodi e visualizzare il testo riconosciuto.
    • Infine, eliminare i nodi riconosciuti da InkAnalyzer e i tratti input penna corrispondenti dall'area di disegno input penna.
    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();
        }
    }
    

Esempi di argomento

Altri esempi