Windows Ink에 기본 제공되는 인식 기능을 사용하여 잉크 스트로크를 텍스트 및 도형으로 변환합니다.
중요 API: InkCanvas, Windows.UI.Input.Inking
잉크 분석을 사용하여 자유 형식 인식
여기서는 Windows Ink 분석 엔진(Windows.UI.Input.Inking.Analysis)을 사용하여 InkCanvas 에서 자유 형식 스트로크 집합을 텍스트 또는 도형으로 분류, 분석 및 인식하는 방법을 보여 줍니다. 텍스트 및 도형 인식 외에도 잉크 분석을 사용하여 문서 구조, 글머리 기호 목록 및 제네릭 드로잉을 인식할 수도 있습니다.
비고
양식 입력과 같은 기본 한 줄 일반 텍스트 시나리오에 대해서는 이 항목의 뒷부분에 나오는 제한된 필기 인식을 참조하십시오.
이 예제에서는 사용자가 단추를 클릭하여 그리기를 완료했음을 나타낼 때 인식이 시작됩니다.
이 샘플을 다운로드: 잉크 분석 샘플(기본)
먼저 UI(MainPage.xaml)를 설정합니다.
UI에는 "인식" 단추, InkCanvas및 표준 Canvas포함됩니다. "인식" 단추를 누르면 잉크 캔버스의 모든 잉크 스트로크가 분석되고(인식되는 경우) 해당 셰이프와 텍스트가 표준 캔버스에 그려집니다. 그러면 잉크 캔버스에서 원래 잉크 스트로크가 삭제됩니다.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0"> <TextBlock x:Name="Header" Text="Basic ink analysis sample" Style="{ThemeResource HeaderTextBlockStyle}" Margin="10,0,0,0" /> <Button x:Name="recognize" Content="Recognize" Margin="50,0,10,0"/> </StackPanel> <Grid x:Name="drawingCanvas" Grid.Row="1"> <!-- The canvas where we render the replacement text and shapes. --> <Canvas x:Name="recognitionCanvas" /> <!-- The canvas for ink input. --> <InkCanvas x:Name="inkCanvas" /> </Grid> </Grid>
UI 코드 비하인드 파일(MainPage.xaml.cs)에서 잉크 및 잉크 분석 기능에 필요한 네임스페이스 형식 참조를 추가합니다.
- Windows.UI.Input.Inking
- Windows.UI.Input.Inking.Analysis
- Windows.UI.Xaml.Shapes
그런 다음, 전역 변수를 지정합니다.
InkAnalyzer inkAnalyzer = new InkAnalyzer(); IReadOnlyList<InkStroke> inkStrokes = null; InkAnalysisResult inkAnalysisResults = null;
다음으로 몇 가지 기본 잉크 입력 동작을 설정합니다.
- InkPresenter 펜, 마우스 및 터치의 입력 데이터를 잉크 스트로크(InputDeviceTypes)로 해석하도록 구성됩니다.
- 지정된 InkDrawingAttributes을(를) 사용하여 InkCanvas 에 잉크 스트로크가 렌더링됩니다.
- "인식" 버튼의 클릭 이벤트에 대한 리스너도 선언됩니다.
/// <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에서 호출하여 현재 모든 잉크 스트로크의 컬렉션을 가져옵니다.
- 잉크 스트로크가 있는 경우 InkAnalyzer의 AddDataForStrokes
호출에 전달합니다. - 드로잉과 텍스트를 모두 인식하려고 하지만 SetStrokeDataKind 메서드를 사용하여 텍스트(문서 구조 및 글머리 기호 목록 포함) 또는 드로잉(도형 인식 포함)에만 관심이 있는지 여부를 지정할 수 있습니다.
- AnalyzeAsync를 호출하여 잉크 분석을 시작하고 InkAnalysisResult를 가져옵니다.
- 상태가 업데이트된상태를 반환하는 경우, InkAnalysisNodeKind.InkWord 및 InkAnalysisNodeKind.InkDrawing모두에 대해 FindNodes를 호출하십시오.
- 두 노드 형식 집합을 반복하고 인식 캔버스(잉크 캔버스 아래)에 해당 텍스트 또는 도형을 그립니다.
- 마지막으로 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 의 스트로크 집합을 텍스트로 변환하는 방법을 보여 줍니다(설치된 기본 언어 팩 기반).
비고
이 섹션에 표시된 기본 필기 인식은 양식 입력과 같은 한 줄 텍스트 입력 시나리오에 가장 적합합니다. 문서 구조, 목록 항목, 도형 및 드로잉(텍스트 인식 외에도)의 분석 및 해석을 포함하는 보다 풍부한 인식 시나리오는 이전 섹션인 잉크 분석을 사용한 자유 형식 인식 섹션을 참조하세요.
이 예제에서는 사용자가 단추를 클릭하여 쓰기가 완료되었음을 나타낼 때 인식이 시작됩니다.
이 샘플을 다운로드하세요 잉크 필기 인식 샘플
먼저 UI를 설정합니다.
UI에는 "인식" 단추, 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>
이 예제에서는 먼저 잉크 기능에 필요한 네임스페이스 형식 참조를 추가해야 합니다.
그런 다음 몇 가지 기본 잉크 입력 동작을 설정합니다.
InkPresenter는 펜과 마우스의 입력 데이터를 잉크 스트로크(InputDeviceTypes)로 해석하도록 구성되어 있습니다. 지정된 InkDrawingAttributes을(를) 사용하여 InkCanvas 에 잉크 스트로크가 렌더링됩니다. "인식" 버튼의 클릭 이벤트에 대한 리스너도 선언됩니다.
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 개체에 저장되었습니다. 스트로크는 StrokeContainer 속성을 통해 InkPresenter에서 노출되고, GetStrokes 메서드를 사용하여 검색됩니다.
// Get all strokes on the InkCanvas. IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
// Create a manager for the InkRecognizer object // used in handwriting recognition. InkRecognizerContainer inkRecognizerContainer = new InkRecognizerContainer();
- RecognizeAsync 호출되어서 InkRecognitionResult 객체 집합을 검색합니다. 인식 결과는 InkRecognizer에 의해 감지된 각 단어에 대해 생성됩니다.
// Recognize all ink strokes on the ink canvas. IReadOnlyList<InkRecognitionResult> recognitionResults = await inkRecognizerContainer.RecognizeAsync( inkCanvas.InkPresenter.StrokeContainer, InkRecognitionTarget.All);
각 InkRecognitionResult 개체에는 텍스트 후보 집합이 포함됩니다. 이 목록의 맨 위 항목은 인식 엔진이 가장 일치하는 항목으로 간주하며, 나머지 후보들은 신뢰도가 줄어드는 순서대로 나열됩니다.
각 InkRecognitionResult를 반복 처리하여 후보 목록을 작성합니다. 그러면 후보자가 표시되고 InkStrokeContainer 지워집니다(이는 InkCanvas도 지웁니다).
string str = "Recognition result\n"; // Iterate through the recognition results. foreach (var result in recognitionResults) { // Get all recognition candidates from each recognition result. IReadOnlyList<string> candidates = result.GetTextCandidates(); str += "Candidates: " + candidates.Count.ToString() + "\n"; foreach (string candidate in candidates) { str += candidate + " "; } } // Display the recognition candidates. recognitionResult.Text = str; // Clear the ink canvas once recognition is complete. inkCanvas.InkPresenter.StrokeContainer.Clear();
- 다음은 전체 클릭 처리기 예제입니다.
// Handle button click to initiate recognition. private async void Recognize_Click(object sender, RoutedEventArgs e) { // Get all strokes on the InkCanvas. IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes(); // Ensure an ink stroke is present. if (currentStrokes.Count > 0) { // Create a manager for the InkRecognizer object // used in handwriting recognition. InkRecognizerContainer inkRecognizerContainer = new InkRecognizerContainer(); // inkRecognizerContainer is null if a recognition engine is not available. if (!(inkRecognizerContainer == null)) { // Recognize all ink strokes on the ink canvas. IReadOnlyList<InkRecognitionResult> recognitionResults = await inkRecognizerContainer.RecognizeAsync( inkCanvas.InkPresenter.StrokeContainer, InkRecognitionTarget.All); // Process and display the recognition results. if (recognitionResults.Count > 0) { string str = "Recognition result\n"; // Iterate through the recognition results. foreach (var result in recognitionResults) { // Get all recognition candidates from each recognition result. IReadOnlyList<string> candidates = result.GetTextCandidates(); str += "Candidates: " + candidates.Count.ToString() + "\n"; foreach (string candidate in candidates) { str += candidate + " "; } } // Display the recognition candidates. recognitionResult.Text = str; // Clear the ink canvas once recognition is complete. inkCanvas.InkPresenter.StrokeContainer.Clear(); } else { recognitionResult.Text = "No recognition results."; } } else { Windows.UI.Popups.MessageDialog messageDialog = new Windows.UI.Popups.MessageDialog("You must install handwriting recognition engine."); await messageDialog.ShowAsync(); } } else { recognitionResult.Text = "No ink strokes to recognize."; } }
국제 인식
Windows 잉크 플랫폼에 기본 제공되는 필기 인식에는 Windows에서 지원하는 광범위한 로캘 및 언어 하위 집합이 포함되어 있습니다.
InkRecognizer.Name 속성 항목에서 InkRecognizer이(가) 지원하는 언어 목록을 참조하세요.
앱은 설치된 필기 인식 엔진 집합을 쿼리하고 그 중 하나를 사용하거나 사용자가 선호하는 언어를 선택하도록 할 수 있습니다.
메모 사용자는 설정 -> 시간 및 언어로 이동하여 설치된 언어 목록을 볼 수 있습니다. 설치된 언어는 언어 아래에 나열 됩니다.
새 언어 팩을 설치하고 해당 언어에 필기 인식을 사용하도록 설정하려면 다음을 수행합니다.
- 설정 > 시간 및 언어 > 지역 및 언어로 이동합니다.
- 언어를 추가선택합니다.
- 목록에서 언어를 선택한 다음, 지역 버전을 선택합니다. 이제 언어가 지역 및 언어 페이지에 나열됩니다.
- 언어를 클릭하고 옵션을 선택합니다.
- 언어 옵션 페이지에서 필기 인식 엔진을 다운로드합니다(여기에서 전체 언어 팩, 음성 인식 엔진 및 키보드 레이아웃을 다운로드할 수도 있음).
여기서는 필기 인식 엔진을 사용하여 선택한 인식기를 기반으로 InkCanvas 스트로크 집합을 해석하는 방법을 보여 줍니다.
사용자가 쓰기를 마치면 단추를 클릭하면 인식이 시작됩니다.
먼저 UI를 설정합니다.
UI에는 "인식" 단추, 설치된 모든 필기 인식기를 나열하는 콤보 상자, 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)로 해석하도록 구성되어 있습니다. 지정된 InkDrawingAttributes을(를) 사용하여 InkCanvas 에 잉크 스트로크가 렌더링됩니다.
함수를
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 개체에 저장되었습니다. 스트로크는 StrokeContainer 속성을 통해 InkPresenter에서 노출되고, GetStrokes 메서드를 사용하여 검색됩니다.
// Get all strokes on the InkCanvas. IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
RecognizeAsync 호출되어서 InkRecognitionResult 객체 집합을 검색합니다.
인식 결과는 InkRecognizer에 의해 감지된 각 단어에 대해 생성됩니다.
// Recognize all ink strokes on the ink canvas. IReadOnlyList<InkRecognitionResult> recognitionResults = await inkRecognizerContainer.RecognizeAsync( inkCanvas.InkPresenter.StrokeContainer, InkRecognitionTarget.All);
각 InkRecognitionResult 개체에는 텍스트 후보 집합이 포함됩니다. 이 목록의 맨 위 항목은 인식 엔진이 가장 일치하는 항목으로 간주하며, 나머지 후보들은 신뢰도가 줄어드는 순서대로 나열됩니다.
각 InkRecognitionResult를 반복 처리하여 후보 목록을 작성합니다. 그러면 후보자가 표시되고 InkStrokeContainer 지워집니다(이는 InkCanvas도 지웁니다).
string str = "Recognition result\n"; // Iterate through the recognition results. foreach (InkRecognitionResult result in recognitionResults) { // Get all recognition candidates from each recognition result. IReadOnlyList<string> candidates = result.GetTextCandidates(); str += "Candidates: " + candidates.Count.ToString() + "\n"; foreach (string candidate in candidates) { str += candidate + " "; } } // Display the recognition candidates. recognitionResult.Text = str; // Clear the ink canvas once recognition is complete. inkCanvas.InkPresenter.StrokeContainer.Clear();
- 다음은 전체 클릭 처리기 예제입니다.
// Handle button click to initiate recognition. private async void Recognize_Click(object sender, RoutedEventArgs e) { // Get all strokes on the InkCanvas. IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes(); // Ensure an ink stroke is present. if (currentStrokes.Count > 0) { // inkRecognizerContainer is null if a recognition engine is not available. if (!(inkRecognizerContainer == null)) { // Recognize all ink strokes on the ink canvas. IReadOnlyList<InkRecognitionResult> recognitionResults = await inkRecognizerContainer.RecognizeAsync( inkCanvas.InkPresenter.StrokeContainer, InkRecognitionTarget.All); // Process and display the recognition results. if (recognitionResults.Count > 0) { string str = "Recognition result\n"; // Iterate through the recognition results. foreach (InkRecognitionResult result in recognitionResults) { // Get all recognition candidates from each recognition result. IReadOnlyList<string> candidates = result.GetTextCandidates(); str += "Candidates: " + candidates.Count.ToString() + "\n"; foreach (string candidate in candidates) { str += candidate + " "; } } // Display the recognition candidates. recognitionResult.Text = str; // Clear the ink canvas once recognition is complete. inkCanvas.InkPresenter.StrokeContainer.Clear(); } else { recognitionResult.Text = "No recognition results."; } } else { Windows.UI.Popups.MessageDialog messageDialog = new Windows.UI.Popups.MessageDialog( "You must install handwriting recognition engine."); await messageDialog.ShowAsync(); } } else { recognitionResult.Text = "No ink strokes to recognize."; } }
동적 인식
이전 두 예제에서는 사용자가 단추를 눌러 인식을 시작해야 하지만 기본 타이밍 함수와 쌍을 이루는 스트로크 입력을 사용하여 동적 인식을 수행할 수도 있습니다.
이 예제에서는 이전 국가별 인식 예제와 동일한 UI 및 스트로크 설정을 사용합니다.
이러한 전역 개체(InkAnalyzer, InkStroke, InkAnalysisResult, DispatcherTimer)는 앱 전체에서 사용됩니다.
// Stroke recognition globals. InkAnalyzer inkAnalyzer; DispatcherTimer recoTimer;
인식을 시작하는 단추 대신 두 개의 InkPresenter 스트로크 이벤트(StrokesCollected 및 StrokeStarted)에 대한 수신기를 추가하고 1초 틱 간격으로 기본 타이머(DispatcherTimer)를 설정합니다.
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 페이지 이벤트
재정의합니다). 획수수집
잉크 획(AddDataForStrokes)을 InkAnalyzer에 추가하고, 사용자가 펜이나 손가락을 떼거나 마우스 단추를 놓아서 잉크 작업을 중지하면 인식 타이머를 시작합니다. 잉크 입력이 없는 1초 후에 인식이 시작됩니다.SetStrokeDataKind 메서드를 사용하여 텍스트(문서 구조 amd 글머리 기호 목록 포함) 또는 드로잉(도형 인식 포함)에만 관심이 있는지 여부를 지정합니다.
획 시작됨
다음 타이머 틱 이벤트 전에 새 스트로크가 시작되면 새 스트로크가 단일 필기 항목의 연속일 가능성이 높기 때문에 타이머를 중지합니다.
// 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(); }
마지막으로 필기 인식을 수행합니다. 이 예제에서는 DispatcherTimer의 Tick 이벤트 처리기를 사용하여 필기 인식을 시작합니다.
- AnalyzeAsync를 호출하여 잉크 분석을 시작하고 InkAnalysisResult를 가져옵니다.
- 상태가 업데이트된상태를 반환하면, 노드 형식 InkAnalysisNodeKind.InkWord에 대해 FindNodes를 호출합니다.
- 노드를 순회하여 인식된 텍스트를 표시합니다.
- 마지막으로 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(); } }
관련 문서
주제 예시
기타 샘플
Windows developer