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

2014年6月28日(土)
薬師寺 国安

手書きの文字を判別して読み上げる

このサンプルでは、文字認識に「Microsoft 日本語手書き認識エンジン」を使用しています。そのため、日本語版Windows 8.1 OS上でしか動作しないので、注意してください。

また、このアプリの操作には、ペンの付属しているタブレットPCが一番適しているかもしれません。タッチディスプレイでないディスプレイでも動作しますが手書き文字をマウスで書く必要があるため、認識率が低下する恐れがあります。

プロジェクト名は「freeHandRecognize」とします。使用するコントロールは表2を参照してください。

表2 使用する主なコントロール

コントロール 名前 役割
Canvas myCanvas この領域に文字を手書きで書く
Button recognizeButton 手書き文字を認識して読み上げるボタン
Button clearButton 手書き文字を消すボタン
MediaElement MediaElement1 読み上げるためのメディア

表2のコントロールをレイアウトすると図3のようになります。

各コントロールをレイアウトした
図3 各コントロールをレイアウトした

書き出されるXAMLをリスト3のように編集します。

リスト3 編集されたXAMLコード(MainPage.xaml)

  • (1) Grid要素をViewBox要素で括る。ViewBoxは、伸縮およびスケーリングを実行して単一の子を使用可能な領域全体に引き伸ばすことができるコンテンツ デコレータを定義する要素です。これによって画面の解像度に応じてオブジェクトのサイズも調整されて表示されるようになる。
  • (2)Canvas要素を配置し、Backgroundで背景色をWhiteにしておく。
  • (3)Button要素を配置し、Contentプロパティに「読み上げる」と指定する。プロパティのIsEnabledにFalseを指定して、最初の状態では使用不可としている。このIsEnabledプロパティは、プロパティのペインの中に表示されない。筆者が見つけることができないだけかもしれないが、そこで、直接Button要素の後ろに半角スぺ—スを入れてプロパティを表示させ、そこから設定している。
  • (4)Button要素を配置し、Contentプロパティに「消去」と指定している。(3)と同じくIsEnabledにはFalseを指定しておく。
  • (5)音声を発するためにMediaElement要素を配置する。
<Page
    x:Class="freeHandRecognize.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:freeHandRecognize"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Viewbox>■(1)
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Width="1363">
            <Canvas x:Name="myCanvas" Background="White" Margin="-31,101,-31,88"/>■(2)
            <StackPanel Orientation="Horizontal" Margin="-31,704,-31,0" Background="Black" Height="100">
                <Button Content="読み上げる" x:Name="recognizeButton"  Height="66"  VerticalAlignment="Bottom" Width="158" FontFamily="Meirio UI" FontSize="24" IsEnabled="False" Background="Navy" Foreground="Pink" Margin="20,0,0,19"/>■(3)
                <Button Content="消去" x:Name="clearButton"  Height="66" VerticalAlignment="Bottom" Width="158" FontFamily="Meirio UI" FontSize="24" IsEnabled="False" Background="Navy" Foreground="Pink" Margin="20,0,0,19"/>■(4)
            </StackPanel>
            <StackPanel HorizontalAlignment="Left" Height="100"  VerticalAlignment="Top" Width="1428" Background="Black" Margin="-31,0" Orientation="Horizontal">
                <TextBlock HorizontalAlignment="Left" Height="91" Margin="19,6,0,3" TextWrapping="Wrap" Text="手書き文字の認識読み上げ" Width="936" FontFamily="Meirio UI" FontSize="72" FontWeight="Bold" Foreground="Crimson"/>
                <MediaElement x:Name="MediaElement1" Height="33" Margin="300,36,0,0" VerticalAlignment="Top" Width="131"/>■(5)
            </StackPanel>
           </Grid>
    </Viewbox>■(1)
</Page>

では、次にMainPage.xaml.vb内にプログラムコードを記述します。

プログラムコード

まず名前空間を読み込みます(リスト4)。

リスト4 名前空間の読み込み

Windows 8のインクシステムをサポートするクラスの含まれる、Windows.UI.Input.Inking名前空間をインポートする。インクストロークを描画する場合等に、この名前空間に含まれるクラスを使用する。

Imports Windows.UI.Input.Inking

タッチ、スタイラス ・ ペン、マウス、およびキーボード デバイス等の入力をサポートするクラスの含まれる、Windows.UI.Input名前空間をインポートする。

Imports Windows.UI.Input

ポインター、タッチ、マウス、およびキーボードを識別し、それらのデバイスに関する情報を取得するクラスの含まれる、 Windows.Devices.Input名前空間をインポートする。

Imports Windows.Devices.Input

図形に関するクラスの含まれる、Windows.UI.Xaml.Shapes名前空間をインポートする。

Imports Windows.UI.Xaml.Shapes

Imports Windows.UI

最新の HTTP アプリケーションのプログラミング インターフェイスを提供するクラスの含まれる、System.Net.Http 名前空間をインポートする。

Imports System.Net.Http

Imports Windows.UI.Popups

Public NotInheritable Class MainPage
    Inherits Page

次にメンバー変数を定義する(リスト5)

リスト5 メンバー変数の定義

ポインター入力位置のクライアント座標を取得して格納する、Point型のメンバー変数prevContactPointを宣言する。(ポインターデバイスが開始された時のポインター入力位置)。Pointクラスは、2 次元の座標系の点をカプセル化するクラスです。

    Private prevContactPoint As Point

入力、操作、および 1 つ以上の(手書きの認識を含む)の処理を管理するプロパティとメソッドを提供するクラスである、 InkManagerクラスのインスタンスである、メンバー変数myInkManagerを宣言する。

    Private myInkManager As New InkManager

入力ポインターの一意の識別子を取得して格納するメンバー変数myPenIDメンバー変数を宣言する。

    Private myPenID As UInteger

ポインター入力位置のクライアント座標を取得して格納する、Pointクラス型のメンバー変数currentContactPointを宣言する(ポインターが移動した時のポインター入力位置)。

    Private currentContactPoint As Point

ポインターデバイスが開始された時のX、Y座標(x1,y1)、ポインターが移動した時のX、Y座標(x2,y2)を格納するDouble型のメンバー変数を宣言しておく。

    Private x1 As Double
    Private x2 As Double
    Private y1 As Double
    Private y2 As Double

手書き文字を認識した結果の文字を入力しておく文字列型のメンバー変数dummyTextBoxを宣言しておく。

    Private dummyTextBox As String

音声として発生する文字を格納する、readingTextメンバー変数を宣言する。

    Private readingText As String

次は、ページがアクティブになった時の処理です(リスト6)

リスト6 ページがアクティブになった時の処理

AddHandlerステートメントで、要素内で、プレスアクションを起こし、ポインターデバイスが開始された時に発生する、PointerPressedイベントに、myCanvas_PointerPressedイベントハンドラを追加する。

AddHandlerステートメントで、要素内で、ポインターが移動した時に発生する、PointerMovedイベントに、myCanvas_PointerMovedイベントハンドラを追加する。

AddHandlerステートメントで、要素内で、プレス アクションを開始したポインター デバイスが離された時に発生するPointerReleasedイベントに、myCanvas_PointerReleasedイベントハンドラを追加する。

AddHandlerステートメントで、要素の領域からポインターが離れた時に発生する、PointerExitedイベントに、myCanvas_PointerReleasedイベントハンドラを追加する。

    Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
        AddHandler myCanvas.PointerPressed, AddressOf myCanvas_PointerPressed
        AddHandler myCanvas.PointerMoved, AddressOf myCanvas_PointerMoved
        AddHandler myCanvas.PointerReleased, AddressOf myCanvas_PointerReleased
        AddHandler myCanvas.PointerExited, AddressOf myCanvas_PointerReleased
    End Sub

次は、要素内で、プレスアクションを起こし、ポインターデバイスが開始された時に発生するイベントの処理です(リスト7)

リスト7 要素内で、プレスアクションを起こし、ポインターデバイスが開始された時に発生するイベントの処理

単一のマウス、ペン/スタイラス、またはタッチに関連付けられた入力のポインターを提供するクラスである、PointerPoint型の変数myPointerを宣言し、GetCurrentPointメソッドで、Canvasの現在のポインターを取得する。PointerPointクラスのPositionプロパティで、ポインター入力の位置のクライアント座標を取得し、メンバー変数prevContactPointに格納する。

現在の、ポインターデバイスのPointerDeviceTypeを取得する。

ポインターデバイスのタイプが、ペン、またはマウス、またはタッチで、かつ、入力がマウスの左ボタン押下、またはその他の入力メソッドの左ボタン押下からであった場合の処理です。[読み上げる]ボタンの使用を可能にする。InkManagerクラスのProcessPointerDownメソッドで、Canvasの、初期の接触位置と圧力、および傾きなどの接触点の位置や機能に関する情報を処理する。InkManagerクラスは、入力、操作、および 1つ以上の処理(手書きの認識を含む)を管理するプロパティとメソッドを提供するクラスです。PointerIdで、入力ポインターの一意の識別子を取得して、メンバー変数myPenIDに格納しておく。

    Private Sub myCanvas_PointerPressed(sender As Object, e As PointerRoutedEventArgs)
        Try
            Dim myPointer As PointerPoint = e.GetCurrentPoint(myCanvas)
            prevContactPoint = myPointer.Position
            Dim myPointerDevType As PointerDeviceType = e.Pointer.PointerDeviceType
            If myPointerDevType = PointerDeviceType.Pen Or myPointerDevType = PointerDeviceType.Mouse Or myPointerDevType = PointerDeviceType.Touch And myPointer.Properties.IsLeftButtonPressed = True Then
                myInkManager.ProcessPointerDown(myPointer)
                myPenID = myPointer.PointerId
                e.Handled = True
            End If
        Catch
            Exit Sub
        End Try
    End Sub

次は、要素内で、ポインターが移動した時に発生するイベントの処理です(リスト8)

  • 音声認識と手書き認識を行うプログラム

    『Windows ストア アプリ 100行プログラミング』 第9回のサンプルプログラムです。
薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています