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 Freihandanalyse

Hier zeigen wir, wie Sie die Windows-Ink-Analyse-Engine (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 die Freihandanalyse auch zur Erkennung von Dokumentenstrukturen, Aufzählungen und allgemeinen Zeichnungen verwendet werden.)

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 Taste klickt, um anzugeben, dass die Zeichnung abgeschlossen ist.

Laden Sie dieses Beispiel aus der Probe für die Freihandanalyse herunter (einfach)

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

    Die Benutzeroberfläche enthält eine Taste „Erkennen“, einen InkCanvas und einen Standard-Kollaborationsbereich. Wenn die Taste „Erkennen“ gedrückt wird, werden alle Freihandstriche auf der Freihandleinwand analysiert und (sofern erkannt) entsprechende Formen und Text auf der Standardleinwand gezeichnet. Die ursprünglichen Freihandstriche werden dann von der Freihandleinwand 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 Namespace-Typverweise 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. Als nächstes legen wir einige grundlegende Verhaltensweisen für die Freihandeingabe 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 Klicken-Event auf der Taste „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 Freihandanalyse im Klick-Event-Handler der Taste „Erkennen“ durch.

    • Rufen Sie zunächst GetStrokes auf dem StrokeContainer des InkCanvas.InkPresenter-Objekts auf, um die Sammlung 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 dasInkAnalysisResult abzurufen.
    • Wenn Status den Status Aktualisiert 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 dem Erkennungszeichenbereich (unterhalb des Freihandzeichenbereichs).
    • Löschen Sie schließlich die erkannten Knoten aus dem InkAnalyzer und die entsprechenden Freihandstriche aus dem Freihandzeichenbereich.
    /// <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 TextBlock auf unserem Erkennungszeichenbereich. Wir verwenden das umgebende Rechteck des zugeordneten Freihandstrichs auf dem Freihandzeichenbereich, 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 Erkennungszeichenbereich. Wir verwenden das umgebende Rechteck des zugeordneten Freihandstrichs auf dem Freihandzeichenbereich, um die Position und den Schriftgrad 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 (Freiformerkennung 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. Formeingaben. Für umfangreichere Erkennungsszenarien, die neben der Texterkennung auch die Analyse und Interpretation von Dokumentstrukturen, Listenelementen, Formen und Zeichnungen umfassen, siehe den vorherigen Abschnitt: Freiformerkennung mit Freihandanalyse.

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

Laden Sie dieses Beispiel aus dem Beispiel für die Schrifterkennung in Freihand 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 Freihandfunktion erforderlich sind:

  3. Dann legen wir einige grundlegende Freihandeingabeverhalten 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 Klicken-Event auf der Taste „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 Klick-Event-Handler der Taste „Erkennen“, um die Schrifterkennung durchzufü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 von der Erkennungs-Engine als die beste Übereinstimmung betrachtet, gefolgt von den übrigen Kandidaten in der Reihenfolge abnehmenden Vertrauens.

      Wir durchlaufen jedes InkRecognitionResult und kompilieren 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-Handlerbeispiel vollständig.
    // 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-Ink-Plattform 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 Schrifterkennungs-Engines abfragen und eines dieser Module verwenden oder dem Benutzer die Auswahl seiner bevorzugten Sprache ermöglichen.

Hinweis: 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 und Sprache > Region und Sprache.
  2. Wählen Sie Eine 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 und Sprache aufgeführt.
  4. Klicken Sie auf die Sprache und wählen Sie Optionen aus.
  5. Laden Sie auf der Seite Sprachoptionen die Schrifterkennungs-Engine herunter (sie können auch das vollständige Sprachpaket, die Spracherkennungs-Engine und die Tastaturbelegung hier herunterladen).

Hier zeigen wir, wie Sie mithilfe der Schrifterkennungs-Engine eine Reihe von Strichen auf einem InkCanvas basierend auf dem ausgewählten Erkennungsmodul interpretieren.

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

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

    Die Benutzeroberfläche enthält eine Taste „Erkennen“, ein Kombinationsfeld mit allen installierten Handschrifterkennungen, 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. Dann legen wir einige grundlegende Freihandeingabeverhalten 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 des Erkennungsmoduls mit einer Liste der installierten Handschrifterkennungen aufzufüllen.

    Außerdem deklarieren wir Listener für das Klick-Event auf der Taste „Erkennen“ und das Auswahländerungs-Event im Kombinationsfeld des Erkennungsmoduls.

     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 des Erkennungsmoduls mit einer Liste der installierten Handschrifterkennungen auf.

    Ein InkRecognizerContainer wird erstellt, um den Schrifterkennungsprozess zu verwalten. Verwenden Sie dieses Objekt, um GetRecognizers aufzurufen und die Liste der installierten Erkennungsmodule abzurufen, um das Kombinationsfeld des Erkennungsmoduls 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 Handschrifterkennung, wenn sich die Auswahl des Kombinationsfelds des Erkennungsmoduls ändert.

    Verwenden Sie den InkRecognizerContainer, um SetDefaultRecognizer basierend auf dem ausgewählten Erkennungsmodul aus dem Kombinationsfeld des Erkennungsmoduls 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 Handschrift-Erkennungsmodul aus. In diesem Beispiel verwenden wir den Klick-Event-Handler der Taste „Erkennen“, um die Schrifterkennung durchzufü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 von der Erkennungs-Engine als die beste Übereinstimmung betrachtet, gefolgt von den übrigen Kandidaten in der Reihenfolge abnehmenden Vertrauens.

      Wir durchlaufen jedes InkRecognitionResult und kompilieren 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-Handlerbeispiel vollständig.
    // 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 Taste drückt, um die Erkennung zu starten, können Sie auch dynamische Erkennung mithilfe von Stricheingaben durchführen, die mit einer einfachen Zeitmessfunktion kombiniert wird.

In diesem Beispiel verwenden wir dieselben Benutzeroberflächen- und Stricheinstellungen wie das vorherige internationale 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 Taste zum Initiieren der Erkennung fügen wir Listener für zwei InkPresenter-Strichevents (StrokesCollected und StrokeStarted) hinzu und richten einen einfachen Timer (DispatcherTimer) mit einem zweiten Takt-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-Events, 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 Erkennungstimer, wenn der Benutzer die Freihandeingabe beendet (durch Heben des Stifts oder Fingers oder Loslassen der Maustaste). Nach einer Sekunde ohne Freihandeingabe wird die Erkennung initiiert.

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

    • StrokeStarted
      Wenn ein neuer Strich vor dem nächsten Timer-Takt-Events beginnt, beenden 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 Takt-Ereignishandler eines DispatcherTimer verwendet, um die Schrifterkennung zu initiieren.

    • Rufen Sie AnalyzeAsync auf, um die Freihandanalyse zu initiieren und dasInkAnalysisResult abzurufen.
    • Wenn Status den Status Aktualisiert 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 dem Freihandzeichenbereich.
    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