WindowsストアアプリのInk機能③
2014年04月18日
前回は、画面上に線を描画する処理を実装しました。
今回は、InkManagerというクラスを利用して、文字認識を行う処理を実装します。
1.コントロールの追加
文字認識に関連したコントロールを、XAMLに記述します。
<Page x:Class="WindowsStoreAppInkSample.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WindowsStoreAppInkSample" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Canvas x:Name="InkCanvas" Background="White" /> <StackPanel Orientation="Vertical" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20,20,0,0"> <TextBlock x:Name="RecognizeText" Foreground="Red" FontSize="18" Text=""/> <TextBlock x:Name="LogText" Foreground="Black" FontSize="18" Text=""/> </StackPanel> <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Bottom" Background="Black"> <Button x:Name="ClearButton" Content="Clear" FontSize="22" Width="200" Height="50" Click="ClearButton_Click" Margin="20,10,20,10"/> <Button x:Name="RecognizeButton" Content="Recognize" FontSize="22" Width="200" Height="50" Margin="20,10,20,10" Click="RecognizeButton_Click"/> <ComboBox x:Name="RecognizerBox" Width="600" FontSize="22" Margin="20,10,20,10"/> </StackPanel> </Grid> </Page>
以下のようなコントロールを追加しました。
RecognizeText :認識した文字を表示するテキストブロック
ClearButton :描画した線を削除するボタン
RecognizeButton :文字認識を行うボタン
RecognizeBox :文字認識に利用するエンジンを選択するコンボボックス
2.InkManagerの定義
InkManagerというクラスを定義します。
このクラスを利用することで、文字認識エンジンの列挙や、文字認識を行うことができます。
InkManager _InkManager = new InkManager();
3.文字認識エンジンの列挙
2で定義したInkManagerを利用し、文字認識エンジンの列挙を行います。
列挙した文字認識エンジンは、RecognizerBoxに設定します。
public MainPage() { this.InitializeComponent(); InkCanvas.PointerPressed += InkCanvas_PointerPressed; InkCanvas.PointerMoved += InkCanvas_PointerMoved; InkCanvas.PointerReleased += InkCanvas_PointerReleased; InkCanvas.PointerExited += InkCanvas_PointerExited; // 文字認識エンジンの列挙 RecognizerBox.DisplayMemberPath = "Name"; IReadOnlyList<InkRecognizer> recognizers = _InkManager.GetRecognizers(); foreach (InkRecognizer recognizer in recognizers) { RecognizerBox.Items.Add(recognizer); } RecognizerBox.SelectedIndex = 0; }
コンボボックスのDisplayMemberPathには「Name」を指定し、InkRecognizerの「Name」プロパティを利用するよう設定します。
4.ポインターイベントの修正
InkManagerはPressed・Move・Releasedのイベント時に、PointerPointを登録することで、内部に線の情報を保存します。
また、InkManagerにも消しゴムのモードが実装されており、線を設定する際にモードを設定すると、消しゴムとして動作させることも可能です。
今回は、デバイスの種類が消しゴムだった場合のみ、消しゴムとして動作させているので、Pressedイベント時にInkManagerのModeを設定しています。
void InkCanvas_PointerPressed(object sender, PointerRoutedEventArgs e) { LogText.Text = "InkCanvas_PointerPressed ----------------------------------------- "; OutputPointerData(e); PointerPoint po = e.GetCurrentPoint(InkCanvas); if (po.PointerDevice.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Pen) { _PenID = po.PointerId; _PrevPoint = po.Position; if (po.Properties.IsEraser) { // 消しゴムモード _InkManager.Mode = InkManipulationMode.Erasing; } else { // ペンモード _InkManager.Mode = InkManipulationMode.Inking; } _InkManager.ProcessPointerDown(po); } e.Handled = true; } void InkCanvas_PointerMoved(object sender, PointerRoutedEventArgs e) { LogText.Text = "InkCanvas_PointerMoved ------------------------------------------- "; OutputPointerData(e); if (e.Pointer.PointerId == _PenID) { PointerPoint po = e.GetCurrentPoint(InkCanvas); Point currentPoint = po.Position; if (GetPointDistance(_PrevPoint, currentPoint) > 0) { ・ ・ ・ _InkManager.ProcessPointerUpdate(po); } } e.Handled = true; } void InkCanvas_PointerReleased(object sender, PointerRoutedEventArgs e) { LogText.Text = "InkCanvas_PointerReleased ---------------------------------------- "; OutputPointerData(e); if (e.Pointer.PointerId == _PenID) { _PenID = 0; _InkManager.ProcessPointerUp(e.GetCurrentPoint(InkCanvas)); } e.Handled = true; }
5.文字認識の処理実装
文字認識は、InkManagerのSetDefaultRecognizerを利用します。
SetDefaultRecognizerを行う前に、SetDefaultRecognizerで文字認識エンジンの設定を行います。
RecognizeAsyncは、名前の通り非同期で実行する必要があるため、async・awaitを利用しています。
文字認識した結果は、複数取得できますので、各結果をカンマ区切りで表示しています。
結果の順番は、最初のものが第一候補となっており、それ以降が第二、第三の候補という順番になっています。
// 文字認識 private async void RecognizeButton_Click(object sender, RoutedEventArgs e) { if (_InkManager.GetStrokes().Count() != 0) { // 文字認識エンジンの設定 _InkManager.SetDefaultRecognizer((InkRecognizer)RecognizerBox.SelectedItem); // 文字認識 string text = ""; IReadOnlyList<InkRecognitionResult> results = await _InkManager.RecognizeAsync(InkRecognitionTarget.All); foreach (InkRecognitionResult result in results) { IReadOnlyList<string> strings = result.GetTextCandidates(); foreach (string s in strings) { if (text.Length != 0) { text += ", "; } text += s; } } // 結果の設定 RecognizeText.Text = text; } }
6.クリアボタンの実装
クリアボタンの実装を行います。
今回は、InkCanvas.Childrenのクリアと、InkManagerを作成し直して対応しました。
// 画面のクリア private void ClearButton_Click(object sender, RoutedEventArgs e) { _InkManager = new InkManager(); InkCanvas.Children.Clear(); }
それでは、実際にアプリケーションを実行し、動作を確認しましょう。
今回は「Microsoft 日本語手書き認識エンジン」という文字認識エンジンを利用して、文字の認識を行いました。
Recognizeボタンを押したあとのスクリーンショットです。
左上の赤字のテキストが、文字認識の結果です。
正常に、「坂本」という文字が認識されていることが分かります。
また、「坂本」以降のテキストは、その他の候補を表示しています。
サンプルソースはこちらにアップしています。
興味のある方は、実際に試して頂ければと思います。
Windows ストアアプリの記事につきましては、今回で終了となります。
次回以降は、また別の内容となりますので、お楽しみに!