Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Converta traços de tinta em texto e formas usando as capacidades de reconhecimento integradas no Windows Ink.
APIs importantes: InkCanvas, Windows.UI.Input.Inking
Reconhecimento de forma livre com análise de tinta
Aqui, demonstramos como usar o motor de análise Windows Ink (Windows.UI.Input.Inink.Analysis) para classificar, analisar e reconhecer um conjunto de traços livres num InkCanvas como texto ou formas. (Para além do reconhecimento de texto e formas, a análise de tinta pode também ser usada para reconhecer estrutura de documentos, listas de tópicos e desenhos genéricos.)
Observação
Para cenários básicos, de linha única e texto simples, como entrada de formulários, veja Reconhecimento de escrita manual restrita mais adiante neste tópico.
Neste exemplo, o reconhecimento é iniciado quando o utilizador clica num botão para indicar que terminou o desenho.
Descarregue esta amostra de análise de tinta (básico)
Primeiro, configurámos a interface (MainPage.xaml).
A interface 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 originais de tinta são então eliminados da tela 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 ficheiro de código-behind da interface de utilizador (MainPage.xaml.cs), adicione as referências de tipo de namespace necessárias para a nossa funcionalidade de tinta e de análise de tinta.
Depois especificamos as nossas variáveis globais:
InkAnalyzer inkAnalyzer = new InkAnalyzer(); IReadOnlyList<InkStroke> inkStrokes = null; InkAnalysisResult inkAnalysisResults = null;De seguida, definimos alguns comportamentos básicos de entrada de tinta:
- O InkPresenter está configurado para interpretar dados de entrada da caneta, rato e toque como traços de tinta (InputDeviceTypes).
- Os traços de tinta são renderizados no InkCanvas usando os InkDrawingAttributes especificados.
- Também é declarado um listener para o evento de clique no botão "Reconhecer".
/// <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; }Neste exemplo, realizamos a análise de tinta no handler de eventos de clique do botão "Reconhecer".
- Primeiro, chame GetStrokes no StrokeContainer do InkCanvas.InkPresenter para obter a coleção de traços de tinta atuais.
- Se houver traços de tinta, envie-os numa chamada para AddDataForStrokes do InkAnalyzer.
- Estamos a tentar reconhecer tanto desenhos como texto, mas pode usar o método SetStrokeDataKind para especificar se está interessado apenas em texto (incluindo estrutura do documento e listas de tópicos) ou apenas em desenhos (incluindo reconhecimento de formas).
- Chame AnalyzeAsync para iniciar a análise de ink e receber o InkAnalysisResult.
- Se o Estado devolver um estado de Atualizado, chame FindNodes tanto para InkAnalysisNodeKind.InkWord como para InkAnalysisNodeKind.InkDrawing.
- Itere por ambos os conjuntos de tipos de nós e desenhe o respetivo texto ou forma na tela de reconhecimento (abaixo da tela de tinta).
- Por fim, elimine os nós reconhecidos do InkAnalyzer e os traços de tinta correspondentes da lona 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 na 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 na 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); }
Aqui está este exemplo em ação:
| Antes da análise | Após análise |
|---|---|
|
|
Reconhecimento de escrita com restrições
Na secção anterior (Reconhecimento livre com análise de tinta), demonstrámos como usar as APIs de análise de tinta para analisar e reconhecer traços de tinta arbitrários dentro de uma área do InkCanvas.
Nesta secção, demonstramos como usar o motor de reconhecimento de escrita manual do Windows Ink (não análise de tinta) para converter um conjunto de traços num InkCanvas em texto (com base no pacote de linguagem por defeito instalado).
Observação
O reconhecimento básico da escrita manual mostrado nesta secção é mais adequado para cenários de entrada de texto de uma linha, como a introdução de formulários. Para cenários de reconhecimento mais ricos que incluam análise e interpretação da estrutura do documento, itens de lista, formas e desenhos (além do reconhecimento de texto), veja a secção anterior: Reconhecimento de forma livre com análise de tinta.
Neste exemplo, o reconhecimento é iniciado quando o utilizador clica num botão para indicar que terminou de escrever.
Descarregue este exemplo do exemplo de reconhecimento de escrita manual Ink
Primeiro, configurámos a interface.
A interface inclui um botão "Reconhecer", o InkCanvas e uma área para mostrar os 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, é necessário primeiro adicionar as referências de tipo de namespace necessárias para a nossa funcionalidade de tinta:
Depois definimos alguns comportamentos básicos de entrada de tinta.
O InkPresenter está configurado para interpretar dados de entrada tanto da caneta como do rato como traços de tinta (InputDeviceTypes). Os traços de tinta são renderizados no InkCanvas usando os InkDrawingAttributes especificados. Também é declarado um listener para o evento de clique no botão "Reconhecer".
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, realizamos o reconhecimento básico da caligrafia. Neste exemplo, usamos o handler de eventos de clique do botão "Reconhecer" para realizar o reconhecimento de escrita manual.
- Um InkPresenter armazena todos os traços de tinta num objeto InkStrokeContainer . Os traços são expostos através da propriedade StrokeContainer do InkPresenter e recuperados usando o método GetStrokes.
// Get all strokes on the InkCanvas. IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();- É criado um InkRecognizerContainer para gerir o processo de reconhecimento de escrita manual.
// Create a manager for the InkRecognizer object // used in handwriting recognition. InkRecognizerContainer inkRecognizerContainer = new InkRecognizerContainer();- RecognizeAsync é chamado para recuperar um conjunto de objetos InkRecognitionResult. São produzidos resultados de reconhecimento para cada palavra detetada 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 motor de reconhecimento como o melhor encaixe, seguido pelos candidatos restantes por ordem de confiança decrescente.
Iteramos através de cada InkRecognitionResult e compilamos a lista de candidatos. Os candidatos são então exibidos e o InkStrokeContainer é limpo (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 completo do manipulador de cliques.
// 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."; } }
Reconhecimento internacional
O reconhecimento de escrita manuscrita incorporado na plataforma Windows Ink inclui um extenso subconjunto de localidades e línguas suportadas pelo Windows.
Consulte o tópico da propriedade InkRecognizer.Name para uma lista de linguagens suportadas pelo InkRerecognizer .
A sua aplicação pode consultar o conjunto de motores de reconhecimento de escrita a mão instalados e usar um deles, ou deixar o utilizador escolher a sua língua preferida.
Nota Os utilizadores podem ver uma lista de línguas instaladas indo a Definições -> Hora e Língua. As línguas instaladas estão listadas em Línguas.
Para instalar novos pacotes de linguagem e permitir o reconhecimento de escrita manual para essa língua:
- Vai a Definições> Hora e Idioma> Região e Idioma.
- Selecionar Adicionar uma língua.
- Selecione uma língua da lista e depois escolha a versão da região. A língua está agora listada na página de Região e língua .
- Clique na língua e selecione Opções.
- Na página de Opções de Idiomas, descarregue o motor de reconhecimento de escrita à mão. Aqui, também pode descarregar o pacote completo de idioma, o motor de reconhecimento de voz e o layout do teclado.
Aqui, demonstramos como usar o motor de reconhecimento de escrita para interpretar um conjunto de traços num InkCanvas com base no reconhecedor selecionado.
O reconhecimento é iniciado pelo utilizador clicar num botão quando termina de escrever.
Primeiro, configurámos a interface.
A interface inclui um botão "Reconhecer", uma caixa combinada que lista todos os reconhecedores de escrita a mão instalados, o InkCanvas e uma área para mostrar os 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>Depois definimos alguns comportamentos básicos de entrada de tinta.
O InkPresenter está configurado para interpretar dados de entrada tanto da caneta como do rato como traços de tinta (InputDeviceTypes). Os traços de tinta são renderizados no InkCanvas usando os InkDrawingAttributes especificados.
Chamamos uma
InitializeRecognizerListfunção para preencher a caixa combinada de reconhecedores com uma lista de reconhecedores de escrita manuscrita instalados.Também declaramos "listeners" para o evento de clique no botão "Reconhecer" e para o evento de seleção alterada na combo box 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 com uma lista de reconhecedores de caligrafia instalados.
É criado um InkRecognizerContainer para gerir o processo de reconhecimento de escrita manual. Use este objeto para chamar o GetRecognizers e recuperar a lista de reconhecedores instalados para preencher a caixa combinada de reconhecedores.
// 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 escrita manual 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.
// Handle recognizer change. private void comboInstalledRecognizers_SelectionChanged( object sender, SelectionChangedEventArgs e) { inkRecognizerContainer.SetDefaultRecognizer( (InkRecognizer)comboInstalledRecognizers.SelectedItem); }Finalmente, realizamos o reconhecimento da caligrafia com base no reconhecedor de caligrafia selecionado. Neste exemplo, usamos o handler de eventos de clique do botão "Reconhecer" para realizar o reconhecimento de escrita manual.
- Um InkPresenter armazena todos os traços de tinta num objeto InkStrokeContainer . Os traços são expostos através da propriedade StrokeContainer do InkPresenter e recuperados usando 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.
São produzidos resultados de reconhecimento para cada palavra detetada 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 motor de reconhecimento como o melhor encaixe, seguido pelos candidatos restantes por ordem de confiança decrescente.
Iteramos através de cada InkRecognitionResult e compilamos a lista de candidatos. Os candidatos são então exibidos e o InkStrokeContainer é limpo (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 completo do manipulador de cliques.
// 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."; } }
Reconhecimento dinâmico
Embora os dois exemplos anteriores exijam que o utilizador pressione um botão para iniciar o reconhecimento, também pode realizar reconhecimento dinâmico usando entrada por traços combinada com função básica de temporização.
Para este exemplo, vamos usar as mesmas definições de interface e traços do exemplo anterior de reconhecimento internacional.
Estes objetos globais (InkAnalyzer, InkStroke, InkAnalysisResult, DispatcherTimer) são usados em toda a nossa aplicação.
// 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 InkPresenter (StrokesCollected e StrokeStarted), e configuramos um temporizador básico (DispatcherTimer) com um intervalo Tick de 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; }Depois definimos os handlers para os eventos InkPresenter que declarámos na primeira etapa (também sobrescrevemos o evento da página OnNavigatingFrom para gerir o nosso temporizador).
StrokesCollected
Adicione traços de tinta (AddDataForStrokes) ao InkAnalyzer e inicie o temporizador de reconhecimento quando o utilizador para de entintar (levantando a caneta ou o dedo, ou soltando o botão do rato). Após um segundo sem entrada de tinta, inicia-se o reconhecimento.Use o método SetStrokeDataKind para especificar se está interessado apenas em texto (incluindo estrutura de documentos e listas de tópicos) ou apenas em desenhos (incluindo reconhecimento de formas).
StrokeStarted
Se um novo traço começar antes do próximo evento de marcação do temporizador, pare o temporizador, pois o novo traço é provavelmente a continuação de uma única entrada de escrita à mão.
// 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(); }Finalmente, realizamos o reconhecimento da caligrafia. Neste exemplo, usamos o gestor de eventos Tick de um DispatcherTimer para iniciar o reconhecimento de escrita manual.
- Chame AnalyzeAsync para iniciar a análise de ink e receber o InkAnalysisResult.
- Se Status devolver um estado de Atualizado, chame FindNodes para tipos de nó do InkAnalysisNodeKind.InkWord.
- Iterar pelos nós e exibir o texto reconhecido.
- Por fim, elimine os nós reconhecidos do InkAnalyzer e os traços de tinta correspondentes da lona 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(); } }
Artigos relacionados
Exemplos de tópicos
- Amostra de análise de tinta (básica) (C#)
- Amostra de reconhecimento de escrita manual com tinta (C#)
Outras amostras
Windows developer