Freigeben über


Erkennen von Windows Ink-Strichen als Text und Formen

Konvertieren Sie Freihandstriche mithilfe der in Windows Ink integrierten Erkennungsfunktionen in Text und Formen.

Wichtige APIs: InkCanvas, Windows.UI.Input.Inking

Freiformerkennung mit Tintenanalyse

Hier zeigen wir, wie Sie das Windows Ink-Analysemodul (Windows.UI.Input.Inking.Analysis) verwenden, um eine Reihe von Freiformstrichen in einem InkCanvas als Text oder Formen zu klassifizieren, zu analysieren und zu erkennen. (Neben der Text- und Formenerkennung kann auch die Freihandanalyse verwendet werden, um Dokumentstruktur, Aufzählungen und generische Zeichnungen zu erkennen.)

Hinweis

Grundlegende, einzeilige Nur-Text-Szenarien wie Formulareingaben finden Sie unter Eingeschränkte Schrifterkennung weiter unten in diesem Thema.

In diesem Beispiel wird die Erkennung initiiert, wenn der Benutzer auf eine Schaltfläche klickt, um anzugeben, dass die Zeichnung abgeschlossen ist.

Laden Sie dieses Beispiel aus dem Beispiel für die Tintenanalyse (einfach) herunter

  1. Zunächst richten wir die Benutzeroberfläche (MainPage.xaml) ein.

    Die Benutzeroberfläche enthält einen "Erkennen"-Button, ein InkCanvas und ein Standard-Canvas. Wenn die Schaltfläche "Erkennen" gedrückt wird, werden alle Freihandstriche auf der Freihandfläche analysiert und (sofern erkannt) entsprechende Formen und Text auf der Standardfläche gezeichnet. Die ursprünglichen Freihandstriche werden dann aus der Zeichenfläche gelöscht.

    <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. Fügen Sie in der CodeBehind-Datei der Benutzeroberfläche (MainPage.xaml.cs) die Namespacetypverweise hinzu, die für unsere Freihand- und Freihandanalysefunktionen erforderlich sind:

  3. Anschließend geben wir unsere globalen Variablen an:

     InkAnalyzer inkAnalyzer = new InkAnalyzer();
     IReadOnlyList<InkStroke> inkStrokes = null;
     InkAnalysisResult inkAnalysisResults = null;
    
  4. Nächstes legen wir einige grundlegende Tinten-Eingabeverhalten fest:

    • Der InkPresenter ist so konfiguriert, dass Eingabedaten von Stift, Maus und Toucheingabe als Freihandstriche (InputDeviceTypes) interpretiert werden.
    • Freihandstriche werden im InkCanvas mithilfe der angegebenen InkDrawingAttributes gerendert.
    • Ein Listener für das Klickereignis auf der Schaltfläche "Erkennen" wird ebenfalls deklariert.
    /// <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. In diesem Beispiel führen wir die Tintenanalyse im Klick-Ereignishandler der Schaltfläche "Erkennen" durch.

    • Rufen Sie zunächst GetStrokes auf dem StrokeContainer des InkCanvas.InkPresenter-Objekts auf, um die Auflistung aller aktuellen Freihandstriche abzurufen.
    • Wenn Freihandstriche vorhanden sind, übergeben Sie sie in einem Aufruf von AddDataForStrokes des InkAnalyzers.
    • Wir versuchen, sowohl Zeichnungen als auch Text zu erkennen, aber Sie können die SetStrokeDataKind-Methode verwenden, um anzugeben, ob Sie nur an Text (einschließlich Dokumentstruktur und Aufzählungen) oder nur an Zeichnungen (einschließlich Formerkennung) interessiert sind.
    • Rufen Sie AnalyzeAsync auf, um die Freihandanalyse zu initiieren und das InkAnalysisResult abzurufen.
    • Wenn Status den Status "Updated" zurückgibt, rufen Sie FindNodes für inkAnalysisNodeKind.InkWord und InkAnalysisNodeKind.InkDrawing auf.
    • Durchlaufen Sie beide Knotentypen und zeichnen Sie den jeweiligen Text oder die jeweilige Form auf den Erkennungsbereich (unterhalb der Freihandfläche).
    • Löschen Sie schließlich die erkannten Knoten aus dem InkAnalyzer und die entsprechenden Freihandstriche aus der Freihandfläche.
    /// <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. Dies ist die Funktion zum Zeichnen eines TextBlocks auf unserer Erkennungs-Canvas. Wir verwenden das begrenzende Rechteck des zugeordneten Freihandstrichs auf der Tintenzeichenfläche, um die Position und den Schriftgrad des TextBlock festzulegen.

     /// <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. Hier sind die Funktionen zum Zeichnen von Ellipsen und Polygonen auf unserem Erkennungscanvas. Wir verwenden das begrenzende Rechteck des zugeordneten Freihandstrichs auf der Freihandzeichenfläche, um die Position und die Schriftgröße der Formen festzulegen.

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

Hier sehen Sie dieses Beispiel in Aktion:

Vor der Analyse Nach analyse
Vor der Analyse Nach analyse

Eingeschränkte Schrifterkennung

Im vorherigen Abschnitt (Freihanderkennung mit Freihandanalyse) haben wir gezeigt, wie Sie mithilfe der Freihandanalyse-APIs beliebige Freihandstriche innerhalb eines InkCanvas-Bereichs analysieren und erkennen können.

In diesem Abschnitt wird veranschaulicht, wie Sie das Windows Ink-Schrifterkennungsmodul (keine Freihandanalyse) verwenden, um eine Reihe von Strichen auf einem InkCanvas in Text zu konvertieren (basierend auf dem installierten Standardsprachpaket).

Hinweis

Die grundlegende Schrifterkennung in diesem Abschnitt eignet sich am besten für einzeilige Texteingabeszenarien wie z. B. Formulareingaben. Ausführlichere Erkennungsszenarien mit Analyse und Interpretation von Dokumentstruktur, Listenelementen, Formen und Zeichnungen (zusätzlich zur Texterkennung) finden Sie im vorherigen Abschnitt: Freiformerkennung mit Freihandanalyse.

In diesem Beispiel wird die Erkennung initiiert, wenn der Benutzer auf eine Schaltfläche klickt, um anzugeben, dass der Schreibvorgang abgeschlossen ist.

Laden Sie dieses Beispiel aus dem Beispiel zur Handschrifterkennung herunter.

  1. Zunächst richten wir die Benutzeroberfläche ein.

    Die Benutzeroberfläche enthält eine Schaltfläche "Erkennen", den InkCanvas und einen Bereich zum Anzeigen von Erkennungsergebnissen.

    <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. In diesem Beispiel müssen Sie zunächst die Namespace-Typverweise hinzufügen, die für unsere Ink-Funktion erforderlich sind.

  3. Anschließend legen wir einige grundlegende Eingabeverhalten für Tinte fest.

    Der InkPresenter ist so konfiguriert, dass Eingabedaten von Stift und Maus als Freihandstriche (InputDeviceTypes) interpretiert werden. Freihandstriche werden im InkCanvas mithilfe der angegebenen InkDrawingAttributes gerendert. Ein Listener für das Klickereignis auf der Schaltfläche "Erkennen" wird ebenfalls deklariert.

    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. Schließlich führen wir die grundlegende Schrifterkennung aus. In diesem Beispiel verwenden wir den Click-Ereignishandler der Schaltfläche "Erkennen", um die Schrifterkennung auszuführen.

    // 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);
    
    • Jedes InkRecognitionResult -Objekt enthält eine Reihe von Textkandidaten. Das oberste Element in dieser Liste wird vom Erkennungsmodul als die beste Übereinstimmung betrachtet, gefolgt von den verbleibenden Kandidaten in der Reihenfolge abnehmender Zuverlässigkeit.

      Wir iterieren durch jedes InkRecognitionResult und erstellen die Liste der Kandidaten. Die Kandidaten werden dann angezeigt und der InkStrokeContainer wird gelöscht (was auch das InkCanvas löscht).

    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();
    
    • Hier sehen Sie das Klick-Handler-Beispiel in voller Länge.
    // 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.";
            }
        }
    

Internationale Anerkennung

Die in die Windows-Freihandplattform integrierte Schrifterkennung umfasst eine umfangreiche Teilmenge von Gebietsschemas und Sprachen, die von Windows unterstützt werden.

Eine Liste der Sprachen, die vom InkRecognizer unterstützt werden, finden Sie im Thema zur InkRecognizer.Name-Eigenschaft.

Ihre App kann den Satz der installierten Schrifterkennungsmodule abfragen und eines dieser Module verwenden, oder dem Benutzer die Auswahl seiner bevorzugten Sprache ermöglichen.

Anmerkung Benutzer können eine Liste der installierten Sprachen anzeigen, indem Sie zu "Einstellungen "> Zeit und Sprache" wechseln. Installierte Sprachen werden unter "Sprachen" aufgeführt.

So installieren Sie neue Sprachpakete und aktivieren die Schrifterkennung für diese Sprache:

  1. Wechseln Sie zu "Einstellungen > Zeit & Sprache > Region & Sprache".
  2. Wählen Sie "Sprache hinzufügen" aus.
  3. Wählen Sie in der Liste eine Sprache aus, und wählen Sie dann die Regionsversion aus. Die Sprache wird jetzt auf der Seite "Region & Sprache " aufgeführt.
  4. Klicken Sie auf die Sprache, und wählen Sie "Optionen" aus.
  5. Laden Sie auf der Seite " Sprachoptionen " das Schrifterkennungsmodul herunter (sie können auch das vollständige Sprachpaket, das Spracherkennungsmodul und das Tastaturlayout hier herunterladen).

Hier zeigen wir, wie Sie mithilfe der Handschrifterkennungsengine eine Reihe von Strichen auf einem InkCanvas basierend auf dem ausgewählten Erkenner interpretieren.

Die Erkennung wird initiiert, wenn der Benutzer auf eine Schaltfläche klickt, wenn er mit dem Schreiben fertig ist.

  1. Zunächst richten wir die Benutzeroberfläche ein.

    Die Benutzeroberfläche enthält eine Schaltfläche "Erkennen", ein Kombinationsfeld mit allen installierten Schrifterkennungen, dem InkCanvas und einem Bereich zum Anzeigen von Erkennungsergebnissen.

    <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. Anschließend legen wir einige grundlegende Eingabeverhalten für Tinte fest.

    Der InkPresenter ist so konfiguriert, dass Eingabedaten von Stift und Maus als Freihandstriche (InputDeviceTypes) interpretiert werden. Freihandstriche werden im InkCanvas mithilfe der angegebenen InkDrawingAttributes gerendert.

    Wir rufen eine InitializeRecognizerList Funktion auf, um das Kombinationsfeld für Handschrifterkennung mit einer Liste der installierten Handschrifterkennungen zu befüllen.

    Außerdem deklarieren wir Listener für das Klick-Ereignis auf der Schaltfläche "Erkennen" und das Auswahländerungsereignis im Erkennungs-Kombinationsfeld.

     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. Wir füllen das Kombinationsfeld für die Erkennung mit einer Liste der installierten Schrifterkennungen auf.

    Ein InkRecognizerContainer wird erstellt, um den Schrifterkennungsprozess zu verwalten. Verwenden Sie dieses Objekt, um GetRecognizers aufzurufen und die Liste der installierten Erkennungen abzurufen, um das Kombinationsfeld für die Erkennung aufzufüllen.

    // 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. Aktualisieren Sie die Schrifterkennung, wenn sich die Auswahl des Kombinationsfelds für die Erkennung ändert.

    Verwenden Sie den InkRecognizerContainer, um SetDefaultRecognizer basierend auf dem ausgewählten Erkenner aus dem Erkenner-Kombinationsfeld aufzurufen.

    // Handle recognizer change.
        private void comboInstalledRecognizers_SelectionChanged(
            object sender, SelectionChangedEventArgs e)
        {
            inkRecognizerContainer.SetDefaultRecognizer(
                (InkRecognizer)comboInstalledRecognizers.SelectedItem);
        }
    
  5. Schließlich führen wir die Schrifterkennung basierend auf dem ausgewählten Schrifterkenner durch. In diesem Beispiel verwenden wir den Click-Ereignishandler der Schaltfläche "Erkennen", um die Schrifterkennung auszuführen.

    // 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);
    
    • Jedes InkRecognitionResult -Objekt enthält eine Reihe von Textkandidaten. Das oberste Element in dieser Liste wird vom Erkennungsmodul als die beste Übereinstimmung angesehen, gefolgt von den verbleibenden Kandidaten in absteigender Vertrauensreihenfolge.

      Wir iterieren durch jedes InkRecognitionResult und erstellen die Liste der Kandidaten. Die Kandidaten werden dann angezeigt und der InkStrokeContainer wird gelöscht (was auch das InkCanvas löscht).

    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();
    
    • Hier sehen Sie das Klick-Handler-Beispiel in voller Länge.
    // 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.";
        }
    }
    

Dynamische Erkennung

Während die beiden vorherigen Beispiele erfordern, dass der Benutzer eine Schaltfläche drückt, um die Erkennung zu starten, können Sie auch dynamische Erkennung mithilfe von Stricheingaben durchführen, die mit einer einfachen Anzeigedauerfunktion gekoppelt sind.

In diesem Beispiel verwenden wir dieselben UI- und Stroke-Einstellungen wie im vorherigen internationalen Erkennungsbeispiel.

  1. Diese globalen Objekte (InkAnalyzer, InkStroke, InkAnalysisResult, DispatcherTimer) werden in unserer gesamten App verwendet.

    // Stroke recognition globals.
    InkAnalyzer inkAnalyzer;
    DispatcherTimer recoTimer;
    
  2. Anstelle einer Schaltfläche zum Initiieren der Erkennung fügen wir Listener für zwei InkPresenter-Strichereignisse (StrokesCollected und StrokeStarted) hinzu und richten einen einfachen Timer (DispatcherTimer) mit einem zweiten Tick-Intervall ein.

    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. Anschließend definieren wir die Handler für die InkPresenter-Ereignisse, die wir im ersten Schritt deklariert haben (wir überschreiben auch das OnNavigatingFrom-Seitenereignis , um unseren Timer zu verwalten).

    • StrokesCollected
      Fügen Sie Freihandstriche (AddDataForStrokes) zum InkAnalyzer hinzu, und starten Sie den Erkennungszeitgeber, wenn der Benutzer die Freihandeingabe beendet (durch Heben des Stifts oder Fingers oder Loslassen der Maustaste). Nach einer Sekunde ohne Tinteneingabe wird die Erkennung gestartet.

      Verwenden Sie die SetStrokeDataKind-Methode, um anzugeben, ob Sie nur an Text (einschließlich Dokumentstruktur und Aufzählungen) oder nur an Zeichnungen (einschließlich der Formerkennung) interessiert sind.

    • StrokeStarted
      Wenn ein neuer Strich vor dem nächsten Timer-Tick beginnt, stoppen Sie den Timer, da der neue Strich wahrscheinlich die Fortsetzung eines einzelnen Handschrifteintrags ist.

    // 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. Schließlich führen wir die Schrifterkennung durch. In diesem Beispiel wird der Tick-Ereignishandler eines DispatcherTimer verwendet, um die Schrifterkennung zu initiieren.

    • Rufen Sie AnalyzeAsync auf, um die Freihandanalyse zu initiieren und das InkAnalysisResult abzurufen.
    • Wenn Status den Status "Updated" zurückgibt, rufen Sie FindNodes für Knotentypen von InkAnalysisNodeKind.InkWord auf.
    • Durchlaufen Sie die Knoten, und zeigen Sie den erkannten Text an.
    • Löschen Sie schließlich die erkannten Knoten aus dem InkAnalyzer und die entsprechenden Freihandstriche aus der Freihandfläche.
    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();
        }
    }
    

Themenbeispiele

Weitere Beispiele