- Статья
- Чтение занимает 17 мин
Преобразуйте росчерки пера в текст и фигуры с помощью встроенных функций распознавания Windows Ink.
Важные API-интерфейсы: InkCanvas, Windows.UI.Input.Inking
Произвольное распознавание с помощью средства анализа рукописного ввода
Здесь мы покажем, как использовать модуль анализа Windows Ink (Windows.UI.Input.Inking.Analysis) для классификации, анализа и распознавания произвольного набора росчерков на InkCanvas как текста или фигур. (Помимо распознавания текста и фигуры, анализ рукописного ввода можно использовать для распознавания структуры документа, маркированных списков и общих рисунков.)
В этом примере распознавание инициируется, когда пользователь нажимает кнопку, чтобы указать, что рисование завершено.
Скачать этот пример из примера анализа рукописного ввода (базовый)
-
Сначала мы настраиваем пользовательский интерфейс (MainPage.xaml).
Пользовательский интерфейс включает кнопку «Распознать», 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 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> -
В этом примере мы сначала добавим ссылки на тип пространства имен, необходимые для наших функций рукописного ввода и его анализа, в файл кода программной части пользовательского интерфейса (MainPage.xaml.cs):
- Windows.UI.Input.Inking
- Windows. Интерфейса. Input. рукописный ввод. анализ
- Windows.UI.Xaml.Shapes
-
Затем мы определим наши глобальные переменные:
InkAnalyzer inkAnalyzer = new InkAnalyzer(); IReadOnlyList<InkStroke> inkStrokes = null; InkAnalysisResult inkAnalysisResults = null; -
Затем мы зададим некоторые основные реакции на рукописный ввод:
- 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; } -
В этом примере мы выполним анализ чернил в обработчике событий нажатия кнопки «Распознать».
- Сначала вызовите GetStrokes на StrokeContainer из InkCanvas.InkPresenter, чтобы получить коллекцию всех текущих росчерков пера.
- Если имеются росчерки пера, передайте их в вызов AddDataForStrokes из InkAnalyzer.
- Мы пытаемся распознать и рисунки, и текст, но вы можете использовать метод SetStrokeDataKind, чтобы указать, интересует ли вас только текст (в том числе структура документа и маркированные списки) или только рисунки (в том числе для распознавания фигур).
- Вызовите AnalyzeAsync для запуска анализа рукописного ввода и получения InkAnalysisResult.
- Если Status возвращает состояние Updated, вызовите 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(); } } } -
Ниже показана функция для рисования 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); } -
Ниже приведены функции для рисования эллипсов и многоугольников на холсте распознавания. Мы используем ограничивающий прямоугольник связанного рукописного штриха на холсте рукописного ввода, чтобы задать расположение и размер шрифта для фигур.
// 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 в текст (в зависимости от установленного языкового пакета по умолчанию).
Примечание
Базовое распознавание рукописного ввода, показанное в этом разделе, лучше всего подходит для сценариев с вводом однострочного текста, например в форму. Для получения сведений о более сложных сценариях распознавания, которые включают анализ и интерпретацию структуры документа, элементы списка, фигуры и рисунки (помимо распознавания текста), см. в предыдущем разделе: Произвольное распознавание с помощью анализа рукописного ввода.
В этом примере распознавание инициируется, когда пользователь нажимает кнопку, чтобы указать, что рукописный ввод завершен.
Загрузить этот пример из примера распознавания рукописного ввода рукописного текста
-
Сначала мы настраиваем пользовательский интерфейс.
Пользовательский интерфейс включает кнопку «Распознать», 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> -
В этом примере необходимо сначала добавить ссылки на тип пространства имен, необходимые для функций рукописного ввода.
- Windows.UI.Input
- Windows.UI.Input.Inking
-
Затем мы задаем некоторые основные реакции на рукописный ввод.
Элемент 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; } -
Наконец, мы выполняем базовое распознавание рукописного ввода. В этом примере для выполнения распознавания рукописного ввода мы используем обработчик событий для нажатия кнопки «Распознать».
- 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();- Рекогнизеасинк вызывается для получения набора объектов инкрекогнитионресулт . Результаты распознавания формируются для каждого слова, обнаруженного инкрекогнизер.
// Recognize all ink strokes on the ink canvas. IReadOnlyList<InkRecognitionResult> recognitionResults = await inkRecognizerContainer.RecognizeAsync( inkCanvas.InkPresenter.StrokeContainer, InkRecognitionTarget.All);-
Каждый объект инкрекогнитионресулт содержит набор текстовых кандидатов. Самый верхний элемент в этом списке рассматривается подсистемой распознавания как наилучшее соответствие, за которой следуют оставшиеся кандидаты в порядке уменьшения достоверности.
Мы перебираем все инкрекогнитионресулт и компилируем список кандидатов. Затем отображаются кандидаты, а инкстрокеконтаинер очищается (что также очищает InkCanvas).
string str = "Recognition resultn"; // 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();- Ниже приведен пример обработчика щелчка Full.
// 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 resultn"; // 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, см. в описании свойства InkRecognizer.Name.
Ваше приложение может запросить набор установленных модулей распознавания рукописного ввода и использовать один из них или позволить пользователю выбрать предпочитаемый язык.
Примечание . пользователи могут просмотреть список установленных языков, перейдя к языку Параметры времени. Установленные языки перечислены в разделе Языки.
Вот как установить новые языковые пакеты и включить распознавание рукописного ввода для конкретного языка.
- выберите язык языковой &> области & Параметры времени.
- Выберите Добавить язык.
- Выберите язык из списка, а затем — региональную версию. Теперь язык указан на странице язык региона .
- Щелкните язык и выберите Параметры.
- На странице Параметры языка скачайте Модуль распознавания рукописного ввода (здесь также можно скачать полный языковой пакет, модуль распознавания речи и раскладку клавиатуры).
Здесь мы покажем, как использовать модуль распознавания рукописного ввода для интерпретации набора росчерков на InkCanvas на основе выбранного распознавателя.
Распознавание вызывается пользователем путем нажатия кнопки после того, как он закончил писать.
-
Сначала мы настраиваем пользовательский интерфейс.
Пользовательский интерфейс включает кнопку «Распознать», поле со списком всех установленных распознавателей рукописного ввода, 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> -
Затем мы задаем некоторые основные реакции на рукописный ввод.
Элемент 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; } -
Мы заполняем поле со списком распознавателя списком установленных распознавателей рукописного ввода.
Объект 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; } } -
Обновите распознаватель рукописного ввода при изменении выбора в поле со списком распознавателя.
Используйте InkRecognizerContainer, чтобы вызвать SetDefaultRecognizer на основе распознавателя, выбранного в поле со списком распознавателя.
// Handle recognizer change. private void comboInstalledRecognizers_SelectionChanged( object sender, SelectionChangedEventArgs e) { inkRecognizerContainer.SetDefaultRecognizer( (InkRecognizer)comboInstalledRecognizers.SelectedItem); } -
Наконец, мы выполняем распознавание рукописного ввода на основе выбранного распознавателя рукописного ввода. В этом примере для выполнения распознавания рукописного ввода мы используем обработчик событий для нажатия кнопки «Распознать».
- InkPresenter сохраняет все росчерки пера в объекте InkStrokeContainer. Росчерки отображаются через свойство StrokeContainerInkPresenter и извлекаются методом GetStrokes.
// 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);-
Каждый объект инкрекогнитионресулт содержит набор текстовых кандидатов. Самый верхний элемент в этом списке рассматривается подсистемой распознавания как наилучшее соответствие, за которой следуют оставшиеся кандидаты в порядке уменьшения достоверности.
Мы перебираем все инкрекогнитионресулт и компилируем список кандидатов. Затем отображаются кандидаты, а инкстрокеконтаинер очищается (что также очищает InkCanvas).
string str = "Recognition resultn"; // 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();- Ниже приведен пример обработчика щелчка Full.
// 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 resultn"; // 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."; } }
Динамическое распознавание
Хотя в двух предыдущих примерах пользователю требуется нажать кнопку для запуска распознавания, вы также может выполнять динамическое распознавание, используя ввод росчерков в сочетании с базовой функцией синхронизации.
В этом примере мы будем использовать тот же пользовательский интерфейс и параметры росчерка, что и в предыдущем примере международного распознавания.
-
Эти глобальные объекты (InkAnalyzer, InkStroke, InkAnalysisResult, DispatcherTimer) часто используются в нашем приложении.
// Stroke recognition globals. InkAnalyzer inkAnalyzer; DispatcherTimer recoTimer; -
Вместо кнопки для запуска распознавания, мы добавили прослушиватели для двух событий росчерка 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; } -
Затем мы определяем обработчики событий InkPresenter, которые мы объявили на первом шаге (мы также переопределим событие страницы OnNavigatingFrom для управления таймером).
-
StrokesCollected
Добавьте росчерки пера (AddDataForStrokes) в InkAnalyzer и запустите таймер распознавания, когда пользователь прерывает рукописный ввод, поднимая перо или палец либо отпуская кнопку мыши. Распознавание вызывается через одну секунду отсутствия рукописного ввода.Используйте метод SetStrokeDataKind, чтобы указать, интересует ли вас только текст (в том числе структура документа и маркированные списки) или только рисунки (в том числе для распознавания фигур).
-
StrokeStarted
Если новый росчерк начинается до следующего события такта таймера, останавливать таймер, так как новый росчерк — это, скорее всего, продолжение одной рукописной записи.
// 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(); } -
-
Наконец, мы выполняем распознавание рукописного ввода. В этом примере мы используем обработчик событий Tick элемента DispatcherTimer для вызова функции распознавания рукописного ввода.
- Вызовите AnalyzeAsync для запуска анализа рукописного ввода и получения InkAnalysisResult.
- Если Status возвращает состояние updated, вызовите финднодес для типов узлов инканалисиснодекинд. инкворд.
- Теперь пройдемся по узлам и покажем распознанный текст.
- И, наконец, удалите распознанные узлы из 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(); } }
Связанные статьи
- Взаимодействие с помощью пера
Примеры в статье
- Пример анализа рукописного ввода (базовый) (C#)
- Пример распознавания рукописного ввода (C#)
Другие примеры
- Простой пример рукописного ввода (C#/C++)
- Сложный пример рукописного ввода (C++)
- Пример рукописного ввода (JavaScript)
- Начало работы учебник. поддержка рукописного ввода в приложении Windows
- Пример раскраски
- Пример семейных заметок
Помните ли вы КПК? Многие уже забыли о том, что такое устройство существовало, да и подросло поколение, которое о существовании этого устройства и не подозревает.
Персональный цифровой помощник более двадцати лет был очень популярным и востребованным устройством, но ровно до момента появления смартфона, который уничтожил КПК, фактически, в один момент.
С чего же всё начиналось.
А началось всё в 70-х годах, двадцатого столетия, когда карманные технологии сделали большой шаг вперёд, благодаря скромному калькулятору, а именно одной конкретной модели — Hewlett Packard HP-65, увидевшему свет в 1974 году. Это был революционный, первый в мире программируемый карманный калькулятор. Благодаря считывателю магнитных карт, позволяющему загружать и сохранять программы.
Спустя шесть лет, индустрия смогла сделать ещё один шаг вперёд, и появилось революционное устройство — Sharp PC-1211. Это был «карманный компьютер» с клавиатурой QUERTY и 24-символьным ЖК-дисплеем, который поддерживал программирование на BASIC. Компания Tandy, для вывода устройства на американский рынок, переименовало PC-1211 в TRS-80 PC1.
Карманные компьютеры долгое время фактически были программируемыми калькуляторами, но в 1982 году компания Hewlett Packard представила новую функцию в своей новой модели HP-75: планировщик встреч. А встроенный будильник наряду с текстовым редактором положили начало созданию персонального цифрового помощника.
Затем в 1984 году компания Psion выпустила Organiser — карманный компьютер с планировщиком и базой данных в прочном корпусе. Впервые появилась возможность хранить контактные данные, вести свой ежедневник, выполнять расчеты и запускать простые программы на ходу. Время работы в автономном режиме измерялось месяцами.
Уже в 1986 году увидел свет Psion Organiser 2, он уже имел операционную систему, язык программирования и порт RS232, для подключения к сторонним системам. Он довольно широко применялся на предприятиях для контроля складов продукции, использовался как валютный калькулятор и т.д.
Портативная вычислительная техника набирала обороты…
К 1989 году рынок портативных устройств начал разделяться на две ветви. Одна ветвь вела к карманным компьютерам: IBM PC совместимые субноутбуки, такие как Poquet PC и Atari Portfolio.
Кстати, простой, легкий и прочный Portfolio был компьютером, с помощью которого Джон Коннор взламывал банкоматы в фильме «Терминатор 2».
Другая ветвь привела к созданию персональных устройств для повышения производительности, таких как Sharp Wizard: карманный органайзер со встроенным планировщиком, блокнотом и телефонной книгой. Пакеты расширения включали словарь, переводчик и тетрис. Однако к его не-QWERTY клавиатуре нужно было привыкнуть.
Тем временем Apple, уволив Стива Джобса в 1985 году, работала над устройством, которому не нужна была клавиатура. Ещё в 1983 году Стив Джобс говорил о необходимости создания «невероятно великолепного компьютера не больше книги, который можно носить с собой». Новый генеральный директор Джон Скалли попытался воплотить идею Джобса в жизнь.
Это было неимоверно сложно. Apple создавала совершенно новое устройство с новой ОС на новом чипе, работающее под управлением нового программного обеспечения с новым пользовательским интерфейсом в новом легком корпусе, изготовленном дизайнерами — как раз в то время, когда все остальные переходили на ноутбуки. Однако они упорно шли к цели и в 1993 году они выпустили его: Newton. Он имел три новых процессора ARM и батарею, которая работала неделями в устройстве в форме блокнота, весившем менее полукилограмма. Вы могли касаться экрана стилусом или писать прямо на нем, так как устройство распознавало рукописный текст.
Но Psion Series 3 уже был на рынке в 1991 году и получил широкое признание. Он имел планировщик, базу данных, текстовый процессор и приложения для работы с электронными таблицами в элегантном корпусе с традиционной клавиатурой. Он был совместим с картами флэш-памяти и работал от батареек типа АА.
Хотел ли кто-нибудь покупать Newton?
Newton был продвинутым устройством, но на старте его распознавание рукописного текста было отстойным. В Doonesbury его высмеивали как игрушку, которая не может правильно читать. Хотя впоследствии эта технология была улучшена, этого было недостаточно; Newton стал первым устройством, которое Стив Джобс уничтожил, когда вернулся в Apple в 1997 году.
Хотя Newton потерпел неудачу, но он ввел в обиход фразу «Personal Digital Assistant» и показал, что распознавание рукописного текста может стать частью пользовательского интерфейса. Одна компания взяла эту идею и воплотила ее в жизнь, хотя для этого пришлось научиться писать по-новому.
Компания Palm была основана в 1992 году Джеффом Хокинсом, который еще в 1989 году разработал систему распознавания письма PalmPrint для перьевого компьютера GrIDPad. Сотрудничая с Tandy и Casio, его новая компания в 1993 году выпустила Zoomer в качестве конкурента Newton, но его постигла та же участь.
Но Хокинс был убежден, что система, управляемая пером с ладони, может работать. Исследования показали, что владельцы Zoomer рассматривают его скорее как аксессуар для ПК, чем как самостоятельный компьютер. Ключом к успеху было создание простого устройства, которое могло бы легко синхронизироваться с ПК.
У Хокинса была еще одна инновация. Граффити — это новый способ письма на КПК, при котором для каждой буквы использовался один росчерк пера. После того, как пользователи научились писать пером (работа заняла 15 минут), точность распознавания символов повысилась. Graffiti была выпущена для Newton в 1994 году и получила положительные отзывы.
В 1995 году компания Palm была куплена US Robotics, и с новым капиталом Хокинс выпустил свой КПК — PalmPilot — в 1996 году. Простой в использовании, интуитивно понятный и легкий PalmPilot мог легко синхронизироваться с ПК и имел целый ряд доступных программ. Это устройство мгновенно стало хитом.
Более поздние PalmPilots имели экраны с подсветкой, беспроводное подключение и цветные дисплеи. Бренд казался непотопляемым, даже после того, как Хокинс покинул Palm и основал конкурирующую компанию Handspring.
Но закат КПК приближался…
В 1999 году компания RIM выпустила модель BlackBerry 850, способную работать с персональной электронной почтой и синхронизироваться с офисной учетной записью электронной почты. Благодаря планировщику, списку задач и базовому браузеру, а также кнопкам для большого пальца на панели и колесом прокрутки, 850-й телефон позволял вести деловую переписку из кармана.
В 2002 году BlackBerry превзошел КПК в качестве основного мобильного инструмента для бизнесменов, выпустив модель 6210 — «Crackberry». Это был телефон, электронная почта, адресная книга и планировщик, который можно было синхронизировать с рабочим аккаунтом. PalmPilot стал вчерашним днём.
А потом появился iPhone, и BlackBerry был отправлен на задворки истории.
Но давайте отдадим должное скромному КПК — он сделал многое для того, что бы современные планшеты и смартфоны появились.












