音声認識と手書き認識を使ってみよう

リスト8 要素内で、ポインターが移動した時に発生するイベントの処理
イベントデータを提供するPointerIdが、入力ポインターの一意の識別子と同じである場合の処理です。
GetCurrentPointメソッドで、Canvasの現在のポインターを取得する。PointerPointクラスのPositionプロパティで、ポインター入力位置のクライアント座標を取得し、メンバー変数currentContactPointに格納する。
メンバー変数x1に、ポインターデバイスが開始された時のX座標を指定する。メンバー変数y1にポインターデバイスが開始された時のY座標を指定する。メンバー変数x2に、要素内で、ポインターが移動した時のX座標を指定する。メンバー変数y2に、要素内で、ポインターが移動した時のY座標を指定する。
新しいLineのインスタンスmyLineオブジェクトを作成する。Line の始点の x 座標に変数x1の値を指定する。Line の始点の y 座標に変数y1の値を指定する。Line の終点の x 座標に変数x2の値を指定する。Line の終点の y 座標に変数y2の値を指定する。Lineの太さを5に指定し、ラインの色を赤に指定する。
要素内で、ポインターが移動した時の、Canvasの現在のポインターをメンバー変数prevContactPointに代入する。CanvasにAddメソッドでmyLineオブジェクトを追加する。InkManagerクラスのProcessPointerUpdateメソッドで、最後のイベントポインターから現在のポインターイベントまでの、圧力と傾きなどの、位置と状態プロパティを更新する。
Private Sub myCanvas_PointerMoved(sender As Object, e As PointerRoutedEventArgs)
If e.Pointer.PointerId = myPenID Then
recognizeButton.IsEnabled = True
clearButton.IsEnabled = True
Dim myPointer As PointerPoint = e.GetCurrentPoint(myCanvas)
currentContactPoint = myPointer.Position
x1 = prevContactPoint.X
y1 = prevContactPoint.Y
x2 = currentContactPoint.X
y2 = currentContactPoint.Y
Dim myLine As New Line
With myLine
.X1 = x1
.Y1 = y1
.X2 = x2
.Y2 = y2
.StrokeThickness = 5
.Stroke = New SolidColorBrush(Colors.Red)
End With
prevContactPoint = currentContactPoint
myCanvas.Children.Add(myLine)
myInkManager.ProcessPointerUpdate(myPointer)
End If
e.Handled = True
End Sub
次は、要素内で、プレス アクションを開始したポインター デバイスが離された時に発生するイベントの処理です(リスト9)。
リスト9 要素内で、プレス アクションを開始したポインター デバイスが離された時に発生するイベントの処理
イベントデータを提供するPointerIdが、入力ポインターの一意の識別子と同じである場合の処理です。GetCurrentPointメソッドで、Canvas内の現在のポインターを取得する。InkManagerクラスのProcessPointerUpメソッドで、ポインターの位置と圧力の傾きを処理する。このメソッドは ProcessPointerUpdateメソッドを呼び出した後で呼び出す必要がある。入力ポインターの一意の識別子を取得していたメンバー変数myPenIDを0で初期化する。
Private Sub myCanvas_PointerReleased(sender As Object, e As PointerRoutedEventArgs)
If e.Pointer.PointerId = myPenID Then
Dim myPointer As PointerPoint = e.GetCurrentPoint(myCanvas)
myInkManager.ProcessPointerUp(myPointer)
End If
myPenID = 0
e.Handled = True
End Sub
次は[消去]ボタンがタップされた時の処理です(リスト10)
リスト10 [消去]ボタンがタップされた時の処理認識された文字が格納されているメンバー変数dummyTextBoxの値を空にする。
InkManagerクラスのModeプロパティで、インク入力モードをInkManipulationMode.Erasingに指定する。ストロークが削除モードになる。InkManagerのGetStrokesメソッドで、InkManager の管理するコレクション内のすべての InkStroke オブジェクトを取得し、変数myStrokeに格納する。
InkStrokeのコレクションの数だけ繰り返し処理を行う。すべてのInkStrokeを選択状態にする。DeleteSelectedメソッドで、選択されたInkStroke オブジェクトを InkManager の管理する InkStroke のコレクションから削除する。Canvasの背景色をWhiteに指定し、Canvas内をクリアする。その後、InkManagerのModeをInkManipulationMode.Inkingに戻しておく。再びインクストロークが可能な状態になる。[読み上げる]と[消去]ボタンの使用を不可とする。
Private Sub clearButton_Click(sender As Object, e As RoutedEventArgs) Handles clearButton.Click
dummyTextBox = String.Empty
myInkManager.Mode = InkManipulationMode.Erasing
Dim myStroke = myInkManager.GetStrokes
For i As Integer = 0 To myStroke.Count - 1
myStroke(i).Selected = True
Next
myInkManager.DeleteSelected()
myCanvas.Background = New SolidColorBrush(Colors.White)
myCanvas.Children.Clear()
myInkManager.Mode = InkManipulationMode.Inking
recognizeButton.IsEnabled = False
clearButton.IsEnabled = False
End Sub
次は、[読み上げる]ボタンがタップされた時の処理です(リスト11)
リスト11 [読み上げる]ボタンがタップされた時の処理
[消去]ボタンの使用を不可とする。InkManagerのGetStrokesメソッドで、InkManager のを管理するコレクション内のすべての InkStroke オブジェクトを取得し、変数myStrokeに格納する。InkStrokeのコレクションの数だけ繰り返し処理を行う。すべてのInkStrokeを選択状態にする。
文字列変数myRecNameを「Microsoft 日本語手書き認識エンジン」で初期化しておく。余談だが、英語の認識エンジンを使用する場合は「Microsoft English (US) Handwriting Recognizer」と指定する。
InkManagerのGetRecognizersメソッドで、手書き認識エンジンのコレクションを取得する。
取得したコレクションの数だけ反復処理を行う。変数myRecNameの値が、手書き認識エンジンのコレクションのNameと一致する場合は、その手書き認識エンジンを、SetDefaultRecognizerメソッドで規定値として設定する。「Microsoft 日本語手書き認識エンジン」が規定値に設定される。RecognizeAsyncメソッドで、1つまたは複数のInkStrokeオブジェクトに対して手書き認識を実行する。InkRecognitionTarget.Allで、ストロークコレクション内のすべてのストロークを認識エンジンに渡す。UpdateRecognitionResultsメソッドで、潜在的なテキストのコレクションが、手書きの認識からマッチするよう更新する。
認識された手書きの結果テキストのコレクション内を反復処理しながら、以下の処理を行う。InkRecognitionResult.GetTextCandidatesメソッドで、手書き認識と一致する可能性のある候補として識別された、文字列のコレクションを取得して、変数myTextに格納する。認識された文字列をdummyTextBoxメンバー変数に格納する。
メンバー変数readingTextに、認識された文字格納されているdummyTextBoxの値を指定する。[消去]ボタンの使用を可能にし、音声で喋らすRecognizeタスクを実行する。非同期処理で行われますので、メソッドの先頭にAsyncを追加する。
Private Async Sub recognizeButton_Click(sender As Object, e As RoutedEventArgs) Handles recognizeButton.Click
clearButton.IsEnabled = False
Dim myStroke = myInkManager.GetStrokes
For i As Integer = 0 To myStroke.Count - 1
myStroke(i).Selected = True
Next
Dim myRecName = "Microsoft 日本語手書き認識エンジン" '"Microsoft English (US) Handwriting Recognizer"
Dim myRecognizer = myInkManager.GetRecognizers
For i As Integer = 0 To myRecognizer.Count - 1
If myRecName = myRecognizer(i).Name Then
myInkManager.SetDefaultRecognizer(myRecognizer(i))
End If
Next
Dim result As IReadOnlyList(Of InkRecognitionResult) = Await myInkManager.RecognizeAsync(InkRecognitionTarget.All)
myInkManager.UpdateRecognitionResults(result)
Dim myAlternate = String.Empty
For Each myResult In result
Dim myText = myResult.GetTextCandidates
myAlternate = myAlternate & " " & myText(0)
dummyTextBox = myAlternate
Next
readingText = dummyTextBox
clearButton.IsEnabled = True
Await Recognize()
End Sub
最後は、認識された手書き文字を音声で読み上げる処理です(リスト12)。
リスト12 認識された手書き文字を音声で読み上げる処理MediaElement型のmyMedia変数を宣言し、MediaElement1で初期化しておく。
音声機能へのアクセスを提供する、新しいSpeechSynthesizerのインスタンス、synthオブジェクトを作成する。SynthesizeTextToStreamAsyncメソッドで、指定した文字列から、音声出力を非同期に生成する。SetSourceメソッドで、指定されたストリームおよびMIME型を使用してSourceプロパティを設定します。Playメソッドで音声を再生する。非同期処理で行われるため、メソッドの先頭にAsyncを追加する。
Private Async Function Recognize() As Task
Dim myMedia As MediaElement = Me.MediaElement1
Dim synth = New Windows.Media.SpeechSynthesis.SpeechSynthesizer
Dim stream = Await synth.SynthesizeTextToStreamAsync(readingText)
myMedia.SetSource(stream, stream.ContentType)
myMedia.Play()
End Function
End Class
実行すると、図4のように表示されます。
今回はこれで終わりです。TextBoxに入力した文字を読み上げる処理と、手書き文字を一度文字に変換して認識し、読み上げる処理を解説しました。2つ目の処理はコードが136行あって、多少長くなってしまいました。また、コード自体も結構複雑なので、何度も読んで理解してほしいと思います。というより、自分でサンプルを見ながらVS2013上で直接コードを打ち込むほうが、何倍も早く身につくので、まずは手を動かして頑張ってください。
最終回の次回は、ローカル画像の読み込み方を解説します。お楽しみに。


