Поделиться через


Распознавание росчерков Windows Ink в виде текста и фигур

Преобразуйте росчерки рукописного ввода в текст и фигуры с помощью возможностей распознавания, встроенных в Windows Ink.

важные API: InkCanvas, Windows.UI.Input.Inking

Распознавание свободной формы с помощью анализа рукописного ввода

Здесь мы покажем, как использовать движок анализа Windows Ink (Windows.UI.Input.Inking.Analysis) для классификации, анализа и распознавания набора штрихов свободной формы на InkCanvas как текст или как фигуры. (Помимо распознавания текста и фигур, анализ рукописного ввода также можно использовать для распознавания структуры документов, маркированных списков и универсальных рисунков.)

Замечание

Основные сценарии для простого однострочного текста, такие как ввод данных в форму, см. в разделе "Ограниченное распознавание рукописного ввода" далее в этом разделе.

В этом примере распознавание инициируется, когда пользователь нажимает кнопку, чтобы указать, что они завершены рисованием.

Скачайте этот пример из раздела анализа чернил (базовый)

  1. Сначала мы настраиваем пользовательский интерфейс (MainPage.xaml).

    Пользовательский интерфейс включает кнопку "Распознать", InkCanvasи стандартный Canvas. При нажатии кнопки "Распознать" все штрихи на холсте рукописного ввода анализируются, и если они распознаны, на стандартном холсте создаются соответствующие фигуры и текст. Затем исходные чернила удаляются с холста.

    <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. В файле кода пользовательского интерфейса (MainPage.xaml.cs) добавьте ссылки на тип пространства имен, необходимые для функций рукописного ввода и анализа рукописных текстов.

  3. Затем мы указываем глобальные переменные:

     InkAnalyzer inkAnalyzer = new InkAnalyzer();
     IReadOnlyList<InkStroke> inkStrokes = null;
     InkAnalysisResult inkAnalysisResults = null;
    
  4. Далее мы установили некоторые базовые параметры рукописного ввода.

    • InkPresenter настроен на интерпретацию входных данных с пера, мыши и касания как рукописные штрихи (InputDeviceTypes).
    • Росчерки рукописного ввода отображаются на inkCanvas с помощью указанного InkDrawingAttributes.
    • Прослушиватель события нажатия кнопки "Распознать" также объявлен.
    /// <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. В этом примере мы выполняем анализ рукописного ввода в обработчике событий нажатия кнопки "Распознать".

    • Сначала вызовите GetStrokes на StrokeContainerInkCanvas.InkPresenter, чтобы получить коллекцию всех текущих росчерков.
    • Если имеются росчерки рукописного ввода, передайте их в вызов AddDataForStrokes из InkAnalyzer.
    • Мы пытаемся распознать как рисунки, так и текст, но можно использовать метод SetStrokeDataKind , чтобы указать, заинтересованы ли вы только в тексте (включая структуру документов и списки маркеров) или только в документах (включая распознавание фигур).
    • Вызовите AnalyzeAsync, чтобы инициировать анализ рукописного ввода и получить результат анализа чернил.
    • Если состояние возвращает состояние Обновлено, вызовите FindNodes для InkAnalysisNodeKind.InkWord и InkAnalysisNodeKind.InkDrawing.
    • Выполните итерацию по обоим наборам типов узлов и нарисуйте соответствующий текст или фигуру на холсте распознавания (под холстом рукописного ввода).
    • Наконец, удалите распознанные узлы из InkAnalyzer и соответствующие росчерки рукописного ввода с холста.
    /// <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. Вот функция для рисования элемента TextBlock на нашем холсте распознавания. Мы используем ограничивающий прямоугольник связанного росчерка на холсте рукописного ввода для задания положения и размера шрифта TextBlock.

     /// <summary>
     /// Draw ink recognition text string on the recognitionCanvas.
     /// </summary>
     /// <param name="recognizedText">The string returned by text recognition.</param>
     /// <param name="boundingRect">The bounding rect of the original ink writing.</param>
     private void DrawText(string recognizedText, Rect boundingRect)
     {
         TextBlock text = new TextBlock();
         Canvas.SetTop(text, boundingRect.Top);
         Canvas.SetLeft(text, boundingRect.Left);
    
         text.Text = recognizedText;
         text.FontSize = boundingRect.Height;
    
         recognitionCanvas.Children.Add(text);
     }
    
  7. Вот функции для рисования эллипсов и многоугольников на нашем холсте распознавания. Мы используем ограничивающий прямоугольник связанного росчерка на холсте рукописного ввода, чтобы задать положение и размер шрифта фигур.

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

Вот этот пример в действии:

Перед анализом После анализа
Перед анализом После анализа

Ограниченное распознавание рукописного ввода

В предыдущем разделе (распознавание свободной формы с анализом рукописного ввода) мы показали, как использовать API анализа рукописного ввода для анализа и распознавания произвольных рукописных штрихов в области InkCanvas.

В этом разделе показано, как использовать модуль распознавания рукописного ввода Windows Ink (не анализ рукописного ввода) для преобразования набора штрихов в текст InkCanvas (на основе установленного языкового пакета по умолчанию).

Замечание

Базовое распознавание рукописного ввода, показанное в этом разделе, лучше всего подходит для однострочных сценариев ввода текста, таких как входные данные формы. Более широкие сценарии распознавания, включающие анализ и интерпретацию структуры документа, элементов списка, фигур и рисунков (помимо распознавания текста), см. в предыдущем разделе: распознавание свободной формы с помощью анализа рукописного ввода.

В этом примере распознавание инициируется, когда пользователь нажимает кнопку, чтобы указать, что они завершают запись.

Скачайте этот образец из примера распознавания текста Ink

  1. Сначала мы настраиваем пользовательский интерфейс.

    Пользовательский интерфейс включает кнопку "Распознать", InkCanvasи область для отображения результатов распознавания.

    <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. В этом примере необходимо сначала добавить ссылки на типы пространства имен, необходимые для функциональности рукописного ввода.

  3. Затем мы задали некоторые базовые параметры рукописного ввода.

    InkPresenter настроен для интерпретации входных данных как от пера, так и от мыши в виде росчерков рукописного ввода (InputDeviceTypes). Росчерки рукописного ввода отображаются на inkCanvas с помощью указанного InkDrawingAttributes. Прослушиватель события нажатия кнопки "Распознать" также объявлен.

    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. Наконец, мы выполняем базовое распознавание рукописного ввода. В этом примере мы используем обработчик событий нажатия кнопки "Распознать" для выполнения распознавания рукописного ввода.

    • InkPresenter сохраняет все росчерки рукописного ввода в объекте InkStrokeContainer. Штрихи предоставляются через свойство StrokeContainerInkPresenter и извлекаются с помощью метода GetStrokes.
    // Get all strokes on the InkCanvas.
        IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
    
    • Для управления процессом распознавания рукописного ввода создается InkRecognizerContainer.
    // Create a manager for the InkRecognizer object
        // used in handwriting recognition.
        InkRecognizerContainer inkRecognizerContainer =
            new InkRecognizerContainer();
    
    • вызывается RecognizeAsync для получения набора объектов InkRecognitionResult. Результаты распознавания формируются для каждого слова, обнаруженного InkRecognizer.
    // Recognize all ink strokes on the ink canvas.
        IReadOnlyList<InkRecognitionResult> recognitionResults =
            await inkRecognizerContainer.RecognizeAsync(
                inkCanvas.InkPresenter.StrokeContainer,
                InkRecognitionTarget.All);
    
    • Каждый объект InkRecognitionResult содержит набор текстовых кандидатов. Самый верхний элемент в этом списке считается механизмом распознавания наиболее подходящим, а затем остальными кандидатами в порядке снижения достоверности.

      Мы итерируем каждую InkRecognitionResult и компилируем список кандидатов. Затем отображаются кандидаты, и InkStrokeContainer очищается (что также очищает InkCanvas).

    string str = "Recognition result\n";
        // Iterate through the recognition results.
        foreach (var result in recognitionResults)
        {
            // Get all recognition candidates from each recognition result.
            IReadOnlyList<string> candidates = result.GetTextCandidates();
            str += "Candidates: " + candidates.Count.ToString() + "\n";
            foreach (string candidate in candidates)
            {
                str += candidate + " ";
            }
        }
        // Display the recognition candidates.
        recognitionResult.Text = str;
        // Clear the ink canvas once recognition is complete.
        inkCanvas.InkPresenter.StrokeContainer.Clear();
    
    • Ниже приведен пример обработчика щелчков в полном объеме.
    // 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.";
            }
        }
    

Международное признание

Распознавание рукописного ввода, встроенное в платформу Windows Ink, включает широкий набор локалей и языков, поддерживаемых Windows.

См. раздел свойств InkRecognizer.Name для списка языков, поддерживаемых InkRecognizer.

Приложение может запрашивать набор установленных обработчиков распознавания рукописного ввода и использовать один из них или позволить пользователю выбрать предпочитаемый язык.

Заметка Пользователи могут просмотреть список установленных языков, перейдя в раздел "Параметры —> время и язык". Установленные языки перечислены в разделе "Языки".

Чтобы установить новые языковые пакеты и включить распознавание рукописного ввода для этого языка:

  1. Перейдите к разделу "Время параметров > " и "Регион языка > " и "Язык".
  2. Выберите "Добавить язык".
  3. Выберите язык из списка, а затем выберите версию региона. Язык теперь указан на странице "Регион и язык ".
  4. Щелкните язык и выберите настройки.
  5. На странице параметров языка скачайте систему распознавания рукописного текста (они также могут скачать полный языковой пакет, подсистему распознавания речи и раскладку клавиатуры).

Здесь мы покажем, как использовать обработчик распознавания рукописного ввода для интерпретации набора штрихов на InkCanvas на основе выбранного распознавателя.

Распознавание инициируется пользователем, щелкнув кнопку после завершения записи.

  1. Сначала мы настраиваем пользовательский интерфейс.

    Пользовательский интерфейс включает кнопку "Распознать", комбинированный список всех установленных распознавателей рукописного ввода, InkCanvasи область для отображения результатов распознавания.

    <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. Затем мы задали некоторые базовые параметры рукописного ввода.

    InkPresenter настроен для интерпретации входных данных как от пера, так и от мыши в виде росчерков рукописного ввода (InputDeviceTypes). Росчерки рукописного ввода отображаются на inkCanvas с помощью указанного InkDrawingAttributes.

    Мы вызываем функцию InitializeRecognizerList, чтобы заполнить выпадающий список с установленными распознавателями рукописного ввода.

    Мы также объявляем обработчики для события нажатия кнопки "Распознать" и события изменения выбора в поле со списком распознавателя.

     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. Комбобокс распознавателей заполняется установленными распознавателями рукописного ввода.

    Для управления процессом распознавания рукописного ввода создается InkRecognizerContainer. Используйте этот объект для вызова GetRecognizers и получения списка установленных распознавателей для заполнения выпадающего списка распознавателей.

    // 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. Обновите распознаватель рукописного ввода при изменении выбора в комбобоксе распознавателя.

    Используйте InkRecognizerContainer для вызова SetDefaultRecognizer на основе выбранного распознавателя из поля со списком распознавателя.

    // Handle recognizer change.
        private void comboInstalledRecognizers_SelectionChanged(
            object sender, SelectionChangedEventArgs e)
        {
            inkRecognizerContainer.SetDefaultRecognizer(
                (InkRecognizer)comboInstalledRecognizers.SelectedItem);
        }
    
  5. Наконец, мы выполняем распознавание рукописного ввода на основе выбранного распознавателя рукописного ввода. В этом примере мы используем обработчик событий нажатия кнопки "Распознать" для выполнения распознавания рукописного ввода.

    • InkPresenter сохраняет все росчерки рукописного ввода в объекте InkStrokeContainer. Штрихи предоставляются через свойство StrokeContainerInkPresenter и извлекаются с помощью метода GetStrokes.
    // Get all strokes on the InkCanvas.
        IReadOnlyList<InkStroke> currentStrokes =
            inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
    
    • вызывается RecognizeAsync для получения набора объектов InkRecognitionResult.

      Результаты распознавания формируются для каждого слова, обнаруженного InkRecognizer.

    // Recognize all ink strokes on the ink canvas.
    IReadOnlyList<InkRecognitionResult> recognitionResults =
        await inkRecognizerContainer.RecognizeAsync(
            inkCanvas.InkPresenter.StrokeContainer,
            InkRecognitionTarget.All);
    
    • Каждый объект InkRecognitionResult содержит набор текстовых кандидатов. Самый верхний элемент в этом списке считается механизмом распознавания наиболее подходящим, а затем остальными кандидатами в порядке снижения достоверности.

      Мы итерируем каждую InkRecognitionResult и компилируем список кандидатов. Затем отображаются кандидаты, и InkStrokeContainer очищается (что также очищает InkCanvas).

    string str = "Recognition result\n";
    // Iterate through the recognition results.
    foreach (InkRecognitionResult result in recognitionResults)
    {
            // Get all recognition candidates from each recognition result.
            IReadOnlyList<string> candidates =
                result.GetTextCandidates();
            str += "Candidates: " + candidates.Count.ToString() + "\n";
            foreach (string candidate in candidates)
            {
                str += candidate + " ";
            }
    }
    // Display the recognition candidates.
    recognitionResult.Text = str;
    // Clear the ink canvas once recognition is complete.
    inkCanvas.InkPresenter.StrokeContainer.Clear();
    
    • Ниже приведен пример обработчика щелчков в полном объеме.
    // 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.";
        }
    }
    

Динамическое распознавание

Хотя в предыдущих двух примерах пользователю требуется нажать кнопку для запуска распознавания, вы также можете выполнять динамическое распознавание с помощью ввода штриха в сочетании с базовой функцией времени.

Для этого примера мы будем использовать те же параметры интерфейса и ширины штриха, как в предыдущем примере международного распознавания.

  1. Эти глобальные объекты (InkAnalyzer, InkStroke, InkAnalysisResult, DispatcherTimer) используются во всем приложении.

    // Stroke recognition globals.
    InkAnalyzer inkAnalyzer;
    DispatcherTimer recoTimer;
    
  2. Вместо кнопки для запуска распознавания мы добавим прослушиватели для двух событий InkPresenter штриха (StrokesCollected и StrokeStarted) и настроим базовый таймер (DispatcherTimer) с интервалом в одну секунду Tick.

    public MainPage()
    {
        this.InitializeComponent();
    
        // Set supported inking device types.
        inkCanvas.InkPresenter.InputDeviceTypes =
            Windows.UI.Core.CoreInputDeviceTypes.Mouse |
            Windows.UI.Core.CoreInputDeviceTypes.Pen;
    
        // Listen for stroke events on the InkPresenter to 
        // enable dynamic recognition.
        // StrokesCollected is fired when the user stops inking by 
        // lifting their pen or finger, or releasing the mouse button.
        inkCanvas.InkPresenter.StrokesCollected += inkCanvas_StrokesCollected;
        // StrokeStarted is fired when ink input is first detected.
        inkCanvas.InkPresenter.StrokeInput.StrokeStarted +=
            inkCanvas_StrokeStarted;
    
        inkAnalyzer = new InkAnalyzer();
    
        // Timer to manage dynamic recognition.
        recoTimer = new DispatcherTimer();
        recoTimer.Interval = TimeSpan.FromSeconds(1);
        recoTimer.Tick += recoTimer_TickAsync;
    }
    
  3. Затем мы определим обработчики событий InkPresenter, объявленных на первом шаге (мы также переопределяем событие страницы OnNavigatingFrom для управления таймером).

    • СобранныеУдары
      Добавьте росчерки рукописного ввода (AddDataForStrokes) в InkAnalyzer и запустите таймер распознавания, когда пользователь останавливает рукописный ввод (поднимая перо или палец или освобождая кнопку мыши). После одной секунды отсутствия ввода инициируется распознавание.

      Используйте метод SetStrokeDataKind, чтобы указать, интересуетесь ли вы только текстом (включая структуру документа и маркированные списки) или только рисунками (включая распознавание фигур).

    • ИнсультНачат
      Если новый штрих начинается до следующего события таймера, остановите таймер, так как новый штрих, вероятно, является продолжением одной записи рукописного ввода.

    // 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. Наконец, мы выполняем распознавание рукописного ввода. В этом примере для запуска распознавания рукописного ввода используется обработчик событий Tick в DispatcherTimer.

    • Вызовите AnalyzeAsync, чтобы инициировать анализ рукописного ввода и получить результат анализа чернил.
    • Если состояния возвращает состояние Обновленного, вызовите FindNodes для типов узлов InkAnalysisNodeKind.InkWord.
    • Выполните итерацию по узлам и отобразите распознанный текст.
    • Наконец, удалите распознанные узлы из InkAnalyzer и соответствующие росчерки рукописного ввода с холста.
    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();
        }
    }
    

Примеры тем

Другие примеры