Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Converta traços de tinta em texto e formas usando os recursos de reconhecimento integrados ao Windows Ink.
APIs importantes: InkCanvas, Windows.UI.Input.Inking
Reconhecimento de forma livre com análise de tinta
Aqui, demonstramos como usar o mecanismo de análise do Windows Ink (Windows.UI.Input.Inking.Analysis) para classificar, analisar e reconhecer um conjunto de traços de forma livre em um InkCanvas como texto ou formas. (Além do reconhecimento de texto e forma, a análise de tinta também pode ser usada para reconhecer estrutura de documentos, listas de marcadores e desenhos genéricos.)
Observação
Para cenários básicos de texto simples de linha única, como entrada de formulário, veja Reconhecimento de manuscrito restrito mais adiante neste tópico.
Neste exemplo, o reconhecimento é iniciado quando o usuário clica em um botão para indicar que concluiu o desenho.
Baixe este exemplo de análise básica de tinta
Primeiro, configuramos a interface do usuário (MainPage.xaml).
A interface do usuário inclui um botão "Reconhecer", um InkCanvas e um Canvas padrão . Quando o botão "Reconhecer" é pressionado, todos os traços de tinta na tela de tinta são analisados e (se reconhecidos) as formas e o texto correspondentes são desenhados na tela padrão. Os traços de tinta originais são excluídos da lona de tinta.
<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>
No arquivo code-behind da interface do usuário (MainPage.xaml.cs), adicione as referências de tipo necessárias para nossa funcionalidade de escrita e análise de tinta:
- Windows.UI.Input.Inking
- Windows.UI.Input.Inking.Analysis
- Windows.UI.Xaml.Shapes
Em seguida, especificamos nossas variáveis globais:
InkAnalyzer inkAnalyzer = new InkAnalyzer(); IReadOnlyList<InkStroke> inkStrokes = null; InkAnalysisResult inkAnalysisResults = null;
Em seguida, definimos alguns comportamentos básicos de entrada de tinta:
- O
InkPresenter é configurado para interpretar dados de entrada de caneta, mouse e toque como traços de tinta ( ).InputDeviceTypes - Traços de tinta são renderizados no InkCanvas usando os InkDrawingAttributesespecificados.
- Um ouvinte para o evento de clique no botão "Reconhecer" também é declarado.
/// <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; }
- O
Para este exemplo, executamos a análise de tinta no manipulador de eventos de clique do botão "Reconhecer".
- Primeiro, chame GetStrokes no StrokeContainer do InkCanvas.InkPresenter para obter a coleção de todos os traços de tinta atuais.
- Se os traços de tinta estiverem presentes, passe-os em uma chamada para AddDataForStrokes do InkAnalyzer.
- Estamos tentando reconhecer desenhos e texto, mas você pode usar o método SetStrokeDataKind para especificar se você está interessado apenas em texto (incluindo estrutura de documentos e listas de marcadores) ou apenas em desenhos (incluindo reconhecimento de forma).
- Chame
para iniciar a análise de tinta e obter oAnalyzeAsync InkAnalysisResult. - Se Status retornar um estado de Atualizado, chame FindNodes para ambos InkAnalysisNodeKind.InkWord e InkAnalysisNodeKind.InkDrawing.
- Iterar em ambos os conjuntos de tipos de nó e desenhar o respectivo texto ou forma na tela de reconhecimento (abaixo da tela de tinta).
- Por fim, exclua os nós reconhecidos do InkAnalyzer e os traços de tinta correspondentes da tela de tinta.
/// <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(); } } }
Aqui está a função para desenhar um TextBlock em nossa tela de reconhecimento. Usamos o retângulo delimitador do traço de tinta associado na tela de tinta para definir a posição e o tamanho da fonte do 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); }
Aqui estão as funções para desenhar elipses e polígonos em nossa tela de reconhecimento. Usamos o retângulo delimitador do traço de tinta associado na tela de tinta para definir a posição e o tamanho da fonte das formas.
// 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); }
Este é o exemplo em ação:
Antes da análise | Após a análise |
---|---|
![]() |
![]() |
Reconhecimento de escrita manual com restrições
Na seção anterior (reconhecimento de forma livre com análise de tinta), demonstramos como usar as APIs de análise de tinta para analisar e reconhecer traços arbitrários de tinta dentro de uma área InkCanvas.
Nesta seção, demonstramos como usar o mecanismo de reconhecimento de manuscrito do Windows Ink (não análise de tinta) para converter um conjunto de traços em um InkCanvas em texto (com base no pacote de idiomas padrão instalado).
Observação
O reconhecimento de manuscrito básico mostrado nesta seção é mais adequado para cenários de entrada de texto de linha única, como entrada de formulário. Para cenários de reconhecimento mais avançados que incluem análise e interpretação da estrutura de documentos, itens de lista, formas e desenhos (além do reconhecimento de texto), consulte a seção anterior: Reconhecimento de forma livre com análise de tinta.
Neste exemplo, o reconhecimento é iniciado quando o usuário clica em um botão para indicar que terminou de gravar.
Baixe este exemplo da amostra de reconhecimento de escrita manual do Ink
Primeiro, configuramos a interface do usuário.
A interface do usuário inclui um botão "Reconhecer", o InkCanvas e uma área para exibir resultados de reconhecimento.
<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>
Para este exemplo, primeiro você precisa adicionar as referências de tipo de namespace necessárias para nossa funcionalidade de tinta:
- windows.ui.input
- Windows.UI.Input.Inking
Em seguida, definimos alguns comportamentos básicos de entrada de tinta.
O InkPresenter é configurado para interpretar dados de entrada tanto de caneta quanto de mouse como traços de tinta (InputDeviceTypes). Traços de tinta são renderizados no InkCanvas usando os InkDrawingAttributesespecificados. Um ouvinte para o evento de clique no botão "Reconhecer" também é declarado.
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; }
Por fim, executamos o reconhecimento de manuscrito básico. Para este exemplo, usamos o manipulador de eventos de clique do botão "Reconhecer" para executar o reconhecimento de manuscrito.
- Um InkPresenter armazena todos os traços de tinta em um objeto InkStrokeContainer. Os traços são expostos através da propriedade
doStrokeContainer InkPresenter e são recuperados utilizando o método .GetStrokes
// Get all strokes on the InkCanvas. IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
- Um InkRecognizerContainer é criado para gerenciar o processo de reconhecimento de manuscrito.
// Create a manager for the InkRecognizer object // used in handwriting recognition. InkRecognizerContainer inkRecognizerContainer = new InkRecognizerContainer();
- RecognizeAsync é chamado para recuperar um conjunto de objetos InkRecognitionResult. Os resultados do reconhecimento são produzidos para cada palavra detectada por um InkRecognizer.
// Recognize all ink strokes on the ink canvas. IReadOnlyList<InkRecognitionResult> recognitionResults = await inkRecognizerContainer.RecognizeAsync( inkCanvas.InkPresenter.StrokeContainer, InkRecognitionTarget.All);
Cada objeto InkRecognitionResult contém um conjunto de candidatos a texto. O item mais alto desta lista é considerado pelo mecanismo de reconhecimento como a melhor correspondência, seguido pelos candidatos restantes em ordem de diminuição da confiança.
Iteramos em cada InkRecognitionResult e compilamos a lista de candidatos. Os candidatos são então exibidos e o InkStrokeContainer é limpo (o que também limpa o 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();
- Aqui está o exemplo do manipulador de cliques, na íntegra.
// 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."; } }
- Um InkPresenter armazena todos os traços de tinta em um objeto InkStrokeContainer. Os traços são expostos através da propriedade
Reconhecimento internacional
O reconhecimento de manuscrito integrado à plataforma de tinta do Windows inclui um amplo subconjunto de localidades e idiomas compatíveis com o Windows.
Consulte o tópico da propriedade InkRecognizer.Name para ver uma lista de idiomas compatíveis com o InkRecognizer.
Seu aplicativo pode consultar o conjunto de mecanismos de reconhecimento de manuscrito instalados e usar um deles ou permitir que um usuário selecione seu idioma preferido.
Nota Os usuários podem ver uma lista de idiomas instalados acessando Configurações –> Tempo & Idioma. Os idiomas instalados são listados em Idiomas.
Para instalar novos pacotes de idiomas e habilitar o reconhecimento de manuscrito para esse idioma:
- Vá para Configurações > Hora e linguagem > Região e Idioma.
- Selecione Adicionar um idioma.
- Selecione um idioma na lista e escolha a versão da região. O idioma agora está listado na página Região & Idioma .
- Clique no idioma e selecione Opções.
- Na página opções
Idioma, baixe o mecanismo de reconhecimento de manuscrito (eles também podem baixar o pacote de idiomas completo, o mecanismo de reconhecimento de fala e o layout do teclado aqui).
Aqui, demonstramos como usar o mecanismo de reconhecimento de manuscrito para interpretar um conjunto de traços em um InkCanvas com base no reconhecedor selecionado.
O reconhecimento é iniciado pelo usuário clicando em um botão quando terminar de gravar.
Primeiro, configuramos a interface do usuário.
A interface do usuário inclui um botão "Reconhecer", uma caixa de combinação que lista todos os reconhecedores de manuscrito instalados, o InkCanvas e uma área para exibir resultados de reconhecimento.
<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>
Em seguida, definimos alguns comportamentos básicos de entrada de tinta.
O InkPresenter é configurado para interpretar dados de entrada tanto de caneta quanto de mouse como traços de tinta (InputDeviceTypes). Traços de tinta são renderizados no InkCanvas usando os InkDrawingAttributesespecificados.
Chamamos uma
InitializeRecognizerList
função para preencher a caixa de combinação do reconhecedor com uma lista de reconhecedores de manuscrito instalados.Também declaramos ouvintes para o evento de clique no botão "Reconhecer" e para o evento de alteração de seleção no campo de seleção do reconhecedor.
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; }
Preenchemos a caixa de combinação do reconhecedor com uma lista de reconhecedores de manuscrito instalados.
Um InkRecognizerContainer é criado para gerenciar o processo de reconhecimento de manuscrito. Use esse objeto para chamar GetRecognizers e recuperar a lista de reconhecedores instalados para preencher a caixa de combinação do reconhecedor.
// 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; } }
Atualize o reconhecedor de manuscrito se a seleção da caixa de combinação do reconhecedor for alterada.
Use o InkRecognizerContainer para chamar SetDefaultRecognizer com base no reconhecedor selecionado da caixa de combinação do reconhecedor.
// Handle recognizer change. private void comboInstalledRecognizers_SelectionChanged( object sender, SelectionChangedEventArgs e) { inkRecognizerContainer.SetDefaultRecognizer( (InkRecognizer)comboInstalledRecognizers.SelectedItem); }
Por fim, executamos o reconhecimento de manuscrito com base no reconhecedor de manuscrito selecionado. Para este exemplo, usamos o manipulador de eventos de clique do botão "Reconhecer" para executar o reconhecimento de manuscrito.
- Um InkPresenter armazena todos os traços de tinta em um objeto InkStrokeContainer. Os traços são expostos através da propriedade
doStrokeContainer InkPresenter e são recuperados utilizando o método .GetStrokes
// Get all strokes on the InkCanvas. IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
RecognizeAsync é chamado para recuperar um conjunto de objetos InkRecognitionResult.
Os resultados do reconhecimento são produzidos para cada palavra detectada por um InkRecognizer.
// Recognize all ink strokes on the ink canvas. IReadOnlyList<InkRecognitionResult> recognitionResults = await inkRecognizerContainer.RecognizeAsync( inkCanvas.InkPresenter.StrokeContainer, InkRecognitionTarget.All);
Cada objeto InkRecognitionResult contém um conjunto de candidatos a texto. O item mais alto desta lista é considerado pelo mecanismo de reconhecimento como a melhor correspondência, seguido pelos candidatos restantes em ordem de diminuição da confiança.
Iteramos em cada InkRecognitionResult e compilamos a lista de candidatos. Os candidatos são então exibidos e o InkStrokeContainer é limpo (o que também limpa o 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();
- Aqui está o exemplo do manipulador de cliques, na íntegra.
// 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."; } }
- Um InkPresenter armazena todos os traços de tinta em um objeto InkStrokeContainer. Os traços são expostos através da propriedade
Reconhecimento dinâmico
Embora os dois exemplos anteriores exijam que o usuário pressione um botão para iniciar o reconhecimento, você também pode executar o reconhecimento dinâmico usando entrada de traços combinada com uma função básica de temporização.
Para este exemplo, usaremos as mesmas configurações de interface e de traço do exemplo anterior de reconhecimento internacional.
Esses objetos globais (InkAnalyzer, InkStroke, InkAnalysisResult, DispatcherTimer) são usados em todo o nosso aplicativo.
// Stroke recognition globals. InkAnalyzer inkAnalyzer; DispatcherTimer recoTimer;
Em vez de um botão para iniciar o reconhecimento, adicionamos ouvintes para dois eventos de traço de
InkPresenter ( eStrokesCollected ) e configuramos um temporizador básico (StrokeStarted ) com um intervalo de deDispatcherTimer um segundo. 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; }
Em seguida, definimos os manipuladores para os eventos InkPresenter que declaramos na primeira etapa (também substituimos o evento de página OnNavigatingFrom para gerenciar nosso temporizador).
Traços Coletados
Adicione traços de tinta (AddDataForStrokes) ao InkAnalyzer e inicie o temporizador de reconhecimento quando o usuário parar de digitar (levantando a caneta ou o dedo ou liberando o botão do mouse). Após um segundo sem entrada de tinta, o reconhecimento é iniciado.Use o método SetStrokeDataKind para especificar se você está interessado apenas em texto (incluindo estrutura do documento e listas de marcadores) ou apenas em desenhos (incluindo reconhecimento de forma).
StrokeStarted
Se um novo traço for iniciado antes do próximo evento de tic do temporizador, pare o temporizador, pois o novo traço provavelmente será a continuação de uma única entrada de manuscrito.
// 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(); }
Por fim, realizamos o reconhecimento de escrita manual. Para este exemplo, usamos o manipulador de eventos Tick de um DispatcherTimer para iniciar o reconhecimento de manuscrito.
- Chame
para iniciar a análise de tinta e obter oAnalyzeAsync InkAnalysisResult. - Se Status retornar um estado de Atualizado, chame FindNodes para tipos de nó de InkAnalysisNodeKind.InkWord.
- Percorrer os nós e exibir o texto reconhecido.
- Por fim, exclua os nós reconhecidos do InkAnalyzer e os traços de tinta correspondentes da tela de tinta.
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(); } }
- Chame
Artigos relacionados
Exemplos de tópico
Outros exemplos
Windows developer