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 Tintenanalyse verwendet werden, um die Dokumentstruktur, Aufzählungen und allgemeine 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 Tintenanalysebeispiel (einfach)

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

    Die Benutzeroberfläche enthält eine Schaltfläche "Erkennen", eine InkCanvas-und eine Standard-Canvas-. Wenn die Schaltfläche "Erkennen" gedrückt wird, werden alle Tintenschläge auf dem Tintenbereich analysiert und (sofern erkannt) entsprechende Text und Formen auf der Standardfläche gezeichnet. Die ursprünglichen Freihandstriche werden dann aus dem Freihandzeichenbereich 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. Als Nächstes legen wir einige Grundeinstellungen für die Stifteingabe fest.

    • Die InkPresenter- ist so konfiguriert, dass Eingabedaten von Stift, Maus und Toucheingabe als Freihandstriche interpretiert werden (InputDeviceTypes).
    • Tintenstriche werden auf dem InkCanvas mit den angegebenen InkDrawingAttributesgerendert.
    • Ein Listener für das Click-Ereignis 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 Ereignis-Handler beim Klick auf die Schaltfläche "Erkennen" aus.

    • Rufen Sie zunächst GetStrokes für den StrokeContainer des InkCanvas.InkPresenter 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 Tintenanalyse zu initiieren und das InkAnalysisResultabzurufen.
    • Wenn Status den Status Updatedliefert, rufen Sie FindNodes sowohl für InkAnalysisNodeKind.InkWord als auch für InkAnalysisNodeKind.InkDrawingauf.
    • Iterieren Sie durch beide Knotentypen und zeichnen Sie den jeweiligen Text oder die jeweilige Form auf der Erkennungsleinwand unterhalb der Freihandleinwand.
    • Löschen Sie schließlich die erkannten Knoten aus dem InkAnalyzer und die entsprechenden Freihandstriche aus dem Zeichenbereich.
    /// <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 Erkennungszeichenfläche. 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 Erkennungscanvas. Wir verwenden das umgebende Rechteck des zugeordneten Freihandstrichs auf der Freihand-Zeichenfläche, 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 (Freihanderkennung mit Freihandanalyse) haben wir gezeigt, wie Sie die Freihandanalyse-APIs verwenden,, um beliebige Freihandstriche innerhalb eines InkCanvas-Bereichs zu analysieren und zu erkennen.

In diesem Abschnitt zeigen wir, wie Sie das Windows Ink-Schrifterkennungsmodul (keine Tintenanalyse) verwenden, um einen Satz 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. Für umfassendere Erkennungsszenarien, die Analyse und Interpretation von Dokumentstrukturen, Listenelementen, Formen und Zeichnungen (zusätzlich zur Texterkennung) umfassen, siehe den obigen Abschnitt: Freiformerkennung mit Tintenanalyse.

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 Muster aus dem Tintenschrifterkennungsmuster herunter

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

    Die Benutzeroberfläche enthält eine Schaltfläche "Erkennen", das 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-Typ-Referenzen hinzufügen, die für die Ink-Funktionalität erforderlich sind.

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

    Die InkPresenter- ist so konfiguriert, dass Eingabedaten von Stift und Maus als Tintenstriche interpretiert werden (InputDeviceTypes). Tintenstriche werden auf dem InkCanvas mit den angegebenen InkDrawingAttributesgerendert. Ein Listener für das Click-Ereignis 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 Klick-Ereignishandler des Buttons "Erkennen", um die Handschriftenerkennung 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 Textkandidaten. Das oberste Element in dieser Liste wird vom Erkennungsmodul als die beste Übereinstimmung betrachtet, gefolgt von den verbleibenden Kandidaten in absteigender Reihenfolge des Vertrauens.

      Wir durchlaufen jedes InkRecognitionResult und kompilieren die Liste der Kandidaten. Die Kandidaten werden dann angezeigt und die InkStrokeContainer- gelöscht (wodurch auch die InkCanvasgelöscht wird).

    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 Klickhandlerbeispiel 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-Freihandplattform integrierte Schrifterkennung umfasst ein umfangreiches Angebot an Gebietsschemas und Sprachen, die von Windows unterstützt werden.

Siehe das Thema zur Eigenschaft InkRecognizer.Name für eine Liste der von InkRecognizer unterstützten Sprachen.

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 sind unter Sprachenaufgelistet.

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 Eine Sprache hinzufügenaus.
  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 Optionenaus.
  5. Laden Sie auf der Seite Sprachoptionen die Handschrifterkennungsmodul herunter (sie können auch das vollständige Sprachpaket, das Spracherkennungsmodul und das Tastaturlayout hier herunterladen).

Hier zeigen wir, wie Sie mithilfe der Schrifterkennungs-Engine eine Reihe von Strichen auf einem InkCanvas- basierend auf dem ausgewählten Erkennungsprogramm 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 umfasst einen "Erkennen"-Button, ein Kombinationsfeld, in dem alle installierten Schrifterkenner aufgelistet sind, das InkCanvas-und einen Bereich zur Anzeige der Erkennungsergebnisse.

    <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.

    Die InkPresenter- ist so konfiguriert, dass Eingabedaten von Stift und Maus als Tintenstriche interpretiert werden (InputDeviceTypes). Tintenstriche werden auf dem InkCanvas mit den angegebenen InkDrawingAttributesgerendert.

    Wir rufen eine InitializeRecognizerList-Funktion auf, um das Kombinationsfeld für die Erkennung mit einer Liste der installierten Schrifterkennungen aufzufüllen.

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

     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 Erkenner mit einer Liste der installierten Handschrifterkenner.

    Um den Schrifterkennungsprozess zu verwalten, wird ein InkRecognizerContainer erstellt. Verwenden Sie dieses Objekt, um GetRecognizers aufzurufen und die Liste der installierten Erkenner abzurufen, um das Recognizer-Kombinationsfeld zu fü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 den Handschrifterkenner, wenn sich die Auswahl im Erkennungs-Kombinationsfeld ändert.

    Verwenden Sie den InkRecognizerContainer, um den SetDefaultRecognizer basierend auf dem ausgewählten Recognizer aus dem Erkennungs-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 Klick-Ereignishandler des Buttons "Erkennen", um die Handschriftenerkennung 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 Textkandidaten. Das oberste Element in dieser Liste wird vom Erkennungsmodul als die beste Übereinstimmung betrachtet, gefolgt von den verbleibenden Kandidaten in absteigender Reihenfolge des Vertrauens.

      Wir durchlaufen jedes InkRecognitionResult und kompilieren die Liste der Kandidaten. Die Kandidaten werden dann angezeigt und die InkStrokeContainer- gelöscht (wodurch auch die InkCanvasgelöscht wird).

    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 Klickhandlerbeispiel 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 bei den beiden vorherigen Beispielen der Benutzer eine Schaltfläche drücken muss, um die Erkennung zu starten, können Sie auch eine dynamische Erkennung mit Stricheingaben und einer grundlegenden Zeitsteuerungsfunktion durchführen.

In diesem Beispiel verwenden wir dieselben Ui- und Stricheinstellungen wie das vorherige internationale Erkennungsbeispiel.

  1. Diese globalen Objekte (InkAnalyzer, InkStroke, InkAnalysisResult, DispatcherTimer) werden in unserer 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 (StrokesCollected und StrokeStarted) hinzu und richten wir einen einfachen Timer (DispatcherTimer) mit einem ein Sekunden-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 Page-Ereignis, um unseren Timer zu verwalten).

    • StricheGesammelt
      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 Tinteingabe wird die Erkennung eingeleitet.

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

    • StrichGestartet
      Wenn ein neuer Strich vor dem nächsten Timer-Tick-Ereignis 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 verwenden wir den Ereignishandler Tick eines DispatcherTimers, um die Handschrifterkennung zu initiieren.

    • Rufen Sie AnalyzeAsync- auf, um die Tintenanalyse zu initiieren und das InkAnalysisResultabzurufen.
    • Wenn Status den Status Updatedzurückgibt, rufen Sie FindNodes für Knotentypen von InkAnalysisNodeKind.InkWordauf.
    • Iterieren Sie durch 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 Zeichenbereich.
    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();
        }
    }
    

Beispiele für Themen

Weitere Beispiele