Windows Ink に組み込まれている認識機能を使用して、インク ストロークをテキストと図形に変換します。
重要な API: InkCanvas、Windows.UI.Input.Inking
インク分析による自由形式認識
ここでは、Windows Ink 分析エンジン (Windows.UI.Input.Inking.Analysis) を使用して、 InkCanvas 上の自由形式ストロークのセットをテキストまたは図形として分類、分析、認識する方法を示します。 (テキストと図形の認識に加えて、インク分析を使用して、ドキュメントの構造、箇条書き、および一般的な図面を認識することもできます)。
注
フォーム入力などの基本的な単一行のプレーン テキスト シナリオについては、このトピックで後述 する「手書き認識の制約 」を参照してください。
この例では、ユーザーがボタンをクリックして描画が完了したことを示すと、認識が開始されます。
Ink 分析サンプル (基本) からこのサンプルをダウンロードしてください。
まず、UI (MainPage.xaml) を設定します。
UI には、"Recognize" ボタン、 InkCanvas、標準 の Canvas が含まれています。 [Recognize]\(認識\) ボタンを押すと、インク キャンバス上のすべてのインク ストロークが分析され、対応する図形とテキストが標準キャンバスに描画されます (認識されている場合)。 その後、元のインク ストロークがインク キャンバスから削除されます。
<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) で、インクおよびインク分析機能に必要な名前空間型参照を追加します。
次に、グローバル変数を指定します。
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; }
この例では、[Recognize]\(認識\) ボタンのクリック イベント ハンドラーでインク分析を実行します。
- まず、InkCanvas.InkPresenter の StrokeContainer で GetStrokes を呼び出して、現在のすべてのインク ストロークのコレクションを取得します。
- インク ストロークが存在する場合は、InkAnalyzer の AddDataForStrokes の呼び出しでそれらを渡します。
- 描画とテキストの両方を認識しようとしていますが、 SetStrokeDataKind メソッドを使用して、テキスト (ドキュメント構造と箇条書きを含む) と描画 (図形認識を含む) のどちらを使用するかを指定できます。
- AnalyzeAsync を呼び出してインク分析を開始し、InkAnalysisResult を取得します。
- 状態が Updated の状態を返す場合は、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 上の一連のストロークを (インストールされている既定の言語パックに基づいて) テキストに変換する方法について説明します。
注
このセクションで示す基本的な手書き認識は、フォーム入力などの 1 行のテキスト入力シナリオに最適です。 ドキュメント構造、リスト アイテム、図形、および描画の分析と解釈 (テキスト認識に加えて) を含む高度な認識シナリオについては、前のセクション「 インク分析による自由形式認識」を参照してください。
この例では、ユーザーがボタンをクリックして、書き込みが完了したことを示したときに認識が開始されます。
まず、UI を設定します。
UI には、[Recognize]\(認識\) ボタン、 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; }
最後に、基本的な手書き認識を実行します。 この例では、"Recognize" ボタンのクリック イベント ハンドラーを使用して、手書き認識を実行します。
- InkPresenter は、すべてのインク ストロークを InkStrokeContainer オブジェクトに格納します。 ストロークは InkPresenter の StrokeContainer プロパティを介して公開され、GetStrokes メソッドを使用して取得されます。
// Get all strokes on the InkCanvas. IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
- 手書き認識プロセスを管理するために InkRecognizerContainer が作成されます。
// Create a manager for the InkRecognizer object // used in handwriting recognition. InkRecognizerContainer inkRecognizerContainer = new InkRecognizerContainer();
- RecognizeAsync は、 InkRecognitionResult オブジェクトのセットを取得するために呼び出されます。 認識結果は、 InkRecognizer によって検出された単語ごとに生成されます。
// Recognize all ink strokes on the ink canvas. IReadOnlyList<InkRecognitionResult> recognitionResults = await inkRecognizerContainer.RecognizeAsync( inkCanvas.InkPresenter.StrokeContainer, InkRecognitionTarget.All);
各 InkRecognitionResult オブジェクトには、一連のテキスト候補が含まれています。 このリストの最上位の項目は、認識エンジンによって最適な一致と見なされ、その後に信頼度が低下する順に残りの候補が続きます。
各 InkRecognitionResult を反復処理し、候補の一覧をコンパイルします。 その後、候補が表示され、 InkStrokeContainer がクリアされます ( InkCanvas もクリアされます)。
string str = "Recognition result\n"; // Iterate through the recognition results. foreach (var result in recognitionResults) { // Get all recognition candidates from each recognition result. IReadOnlyList<string> candidates = result.GetTextCandidates(); str += "Candidates: " + candidates.Count.ToString() + "\n"; foreach (string candidate in candidates) { str += candidate + " "; } } // Display the recognition candidates. recognitionResult.Text = str; // Clear the ink canvas once recognition is complete. inkCanvas.InkPresenter.StrokeContainer.Clear();
- 完全なクリック ハンドラーの例を次に示します。
// Handle button click to initiate recognition. private async void Recognize_Click(object sender, RoutedEventArgs e) { // Get all strokes on the InkCanvas. IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes(); // Ensure an ink stroke is present. if (currentStrokes.Count > 0) { // Create a manager for the InkRecognizer object // used in handwriting recognition. InkRecognizerContainer inkRecognizerContainer = new InkRecognizerContainer(); // inkRecognizerContainer is null if a recognition engine is not available. if (!(inkRecognizerContainer == null)) { // Recognize all ink strokes on the ink canvas. IReadOnlyList<InkRecognitionResult> recognitionResults = await inkRecognizerContainer.RecognizeAsync( inkCanvas.InkPresenter.StrokeContainer, InkRecognitionTarget.All); // Process and display the recognition results. if (recognitionResults.Count > 0) { string str = "Recognition result\n"; // Iterate through the recognition results. foreach (var result in recognitionResults) { // Get all recognition candidates from each recognition result. IReadOnlyList<string> candidates = result.GetTextCandidates(); str += "Candidates: " + candidates.Count.ToString() + "\n"; foreach (string candidate in candidates) { str += candidate + " "; } } // Display the recognition candidates. recognitionResult.Text = str; // Clear the ink canvas once recognition is complete. inkCanvas.InkPresenter.StrokeContainer.Clear(); } else { recognitionResult.Text = "No recognition results."; } } else { Windows.UI.Popups.MessageDialog messageDialog = new Windows.UI.Popups.MessageDialog("You must install handwriting recognition engine."); await messageDialog.ShowAsync(); } } else { recognitionResult.Text = "No ink strokes to recognize."; } }
国際的な認識
Windows インク プラットフォームに組み込まれている手書き認識には、Windows でサポートされているロケールと言語の広範なサブセットが含まれています。
InkRecognizer でサポートされている言語の一覧については、InkRecognizer.Name プロパティのトピックを参照してください。
アプリでは、インストールされている一連の手書き認識エンジンに対してクエリを実行し、そのうちの 1 つを使用したり、ユーザーが優先する言語を選択したりできます。
手記 ユーザーは 、[設定] -> [時刻] と [言語] に移動して、インストールされている言語の一覧を表示できます。 インストールされている言語は、[言語] の下 に表示されます。
新しい言語パックをインストールし、その言語の手書き認識を有効にするには:
- [ 設定] > [時間] と [言語] > [地域と言語] に移動します。
- [言語を追加]を選択します。
- 一覧から言語を選択し、リージョンのバージョンを選択します。 言語が [ 地域と言語 ] ページに一覧表示されます。
- 言語をクリックし、[ オプション] を選択します。
- [ 言語オプション ] ページで、 手書き認識エンジンを ダウンロードします (完全な言語パック、音声認識エンジン、キーボード レイアウトもダウンロードできます)。
ここでは、手書き認識エンジンを使用して、選択した認識エンジンに基づいて InkCanvas 上のストロークのセットを解釈する方法を示します。
認識は、ユーザーが書き込みが完了したときにボタンをクリックすることによって開始されます。
まず、UI を設定します。
UI には、"Recognize" ボタン、インストールされているすべての手書き認識エンジン、 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); }
最後に、選択した手書き認識エンジンに基づいて手書き認識を実行します。 この例では、"Recognize" ボタンのクリック イベント ハンドラーを使用して、手書き認識を実行します。
- InkPresenter は、すべてのインク ストロークを InkStrokeContainer オブジェクトに格納します。 ストロークは InkPresenter の StrokeContainer プロパティを介して公開され、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."; } }
動的認識
前の 2 つの例では、ユーザーがボタンを押して認識を開始する必要があります。また、基本的なタイミング関数と組み合わせてストローク入力を使用して動的認識を実行することもできます。
この例では、前の国際認識の例と同じ UI とストローク設定を使用します。
これらのグローバル オブジェクト (InkAnalyzer、 InkStroke、 InkAnalysisResult、 DispatcherTimer) は、アプリ全体で使用されます。
// Stroke recognition globals. InkAnalyzer inkAnalyzer; DispatcherTimer recoTimer;
認識を開始するボタンの代わりに、2 つの 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 ページ イベントもオーバーライドします)。
線の収集
InkAnalyzer にインク ストローク (AddDataForStrokes) を追加し、ユーザーが手書き入力を停止したときに認識タイマーを開始します (ペンまたは指を持ち上げたり、マウス ボタンを離したりします)。 インク入力がない 1 秒後、認識が開始されます。SetStrokeDataKind メソッドを使用して、テキスト (ドキュメント構造 amd 箇条書きを含む) または描画 (図形認識を含む) のみに関心があるかどうかを指定します。
ストローク開始
次のタイマー ティック イベントの前に新しいストロークが開始された場合は、新しいストロークが 1 つの手書き入力の継続である可能性が高いタイマーを停止します。
// 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