WPFのインク機能③

2013年12月12日

LINEで送る

今回は、InkCanvasで書いた文字を認識する方法を紹介します。
文字認識を行う場合、プログラムの実装だけではなく、環境の構築が必要となります。

1. Windows SDKのインストール
Windows SDK for Vistaをインストールします。
必要なDLLはWindows 7・8のSDKには入っていませんので、注意してください。
Windows SDK for Vistaはこちらのサイトからダウンロードできます。

2. DLLの参照設定
インストール後、以下のDLLを参照するよう設定してください。

・IACore.dll
・IAWinFX.dll
・IALoader.dll

私の環境では、以下のパスとなっていました。

C:\Program Files\Reference Assemblies\Microsoft\Tablet PC\v1.7\IACore.dll
C:\Program Files\Reference Assemblies\Microsoft\Tablet PC\v1.7\IAWinFx.dll
C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\IALoader.dll

3. プラットフォームターゲットの変更
参照設定に追加後、まずは一回ビルドを行ってみてください。
ビルドは行えるのですが、以下のようなwarningが表示されているかと思います。

warning MSB3270: 構築されているプロジェクトのプロセッサ アーキテクチャ “MSIL” と、参照 “IAWinFX, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=x86″ のプロセッサ アーキテクチャ “x86″ の間には不一致がありました。
この不一致は、ランタイム エラーを発生させる可能性があります。
プロジェクトと参照の間でプロセッサ アーキテクチャが一致するように、構成マネージャーを使用してターゲットとするプロジェクトのプロセッサ アーキテクチャを変更するか、ターゲットとするプロジェクトのプロセッサ アーキテクチャに一致するプロジェクト アーキテクチャとの依存関係を参照で設定することを検討してください。

これはIAWinFX.dllが64bitに対応していないため発生しています。
WPFのアプリケーションはデフォルトで「Any CPU」となっており、32bitと64bitの両方に対応しています。
IAWinFX.dllが32bitに対応していないので、アプリケーション自体を32bitのみに設定する必要があります。
プロジェクトのプロパティを表示し、「ビルド」の「プラットフォームターゲット」を「x86」に設定します。
再度、ビルドを行うとwarningが表示されなくなっているかと思います。

4. インストールされている文字認識エンジンの取得
ここから実際にコードを記述していきます。
まずは、文字認識エンジンの一覧を取得し、ListBoxに表示する部分を実装します。
前回設置したボタンの下にListBoxと文字認識を行うボタンをXAML上に設置します。

<StackPanel Orientation="Vertical" Background="Gray" Grid.Column="1">
    <Button x:Name="eraseByPointBtn" Content="EraseByPoint" Click="eraseByPointBtn_Click"/>
    <Button x:Name="eraseByStrokeBtn" Content="EraseByStroke" Click="eraseByStrokeBtn_Click"/>
    <Button x:Name="gestureOnlyBtn" Content="GestureOnly" Click="gestureOnlyBtn_Click"/>
    <Button x:Name="inkBtn" Content="Ink" Click="inkBtn_Click"/>
    <Button x:Name="inkAndGestureBtn" Content="InkAndGesture" Click="inkAndGestureBtn_Click"/>
    <Button x:Name="noneBtn" Content="None" Click="noneBtn_Click"/>
    <Button x:Name="selectBtn" Content="Select" Click="selectBtn_Click"/>
    <!-- 保存機能 -->
    <Button x:Name="saveBtn" Content="Save" Margin="0,10,0,0" Click="saveBtn_Click"/>
    <Button x:Name="openBtn" Content="Open" Click="openBtn_Click"/>
    <!-- 文字認識機能 -->
    <ListBox x:Name="recognizerListBox" Margin="0,10,0,0" Height="150px" DisplayMemberPath="Name" SelectedValuePath="Guid"/>
    <Button x:Name="recognizerBtn" Content="文字認識" Click="recognizerBtn_Click" />
</StackPanel>

次に、ListBoxに文字認識エンジンの一覧を表示するコードを追記します。
サンプルではコンストラクタ内に追加しています。

try
{
    // インストールされている文字認識エンジンの取得
    InkAnalyzer analyzer = new InkAnalyzer();
    InkRecognizerCollection recognizerList = analyzer.GetInkRecognizersByPriority();
    foreach (InkRecognizer recognizer in recognizerList)
    {
        recognizerListBox.Items.Add(recognizer);
    }
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

InkRecognizerを直接ListBoxに追加していますが、
XAML上でDisplayMemberPath、SelectedValuePathというプロパティを設定しているため、
ListBox上に表示されるのはInkRecognizerのNameプロパティ、
SelectedValueとして利用するのはInkRecognizerのGuidプロパティとなります。

5. 文字認識の実装
文字認識ボタンのイベントに処理を追加します。
ListBox上で選択した文字認識エンジンを利用して、InkCanvasに書いた文字を認識しています。

private void recognizerBtn_Click(object sender, RoutedEventArgs e)
{
    if (recognizerListBox.SelectedIndex != -1)
    {
        // 選択した文字認識エンジンのGUIDを取得
        Guid guid = (Guid)recognizerListBox.SelectedValue;

        // GUIDから文字認識エンジンを指定する
        InkAnalyzer analyzer = new InkAnalyzer();
        CustomRecognizerNode node = analyzer.CreateCustomRecognizer(guid);

        // InkCanvasのストローク設定
        analyzer.AddStrokesToCustomRecognizer(inkCanvas.Strokes, node);
        analyzer.SetStrokesType(inkCanvas.Strokes, StrokeType.Writing);

        // 文字認識
        analyzer.Analyze();

        // 第一候補の表示
        MessageBox.Show(analyzer.GetRecognizedString());

        // 第一候補を含む文字列の出力
        AnalysisAlternateCollection alternateList = analyzer.GetAlternates();
        foreach (AnalysisAlternate alternate in alternateList)
        {
            System.Diagnostics.Debug.WriteLine(alternate.RecognizedString);
        }
    }
    else
    {
        MessageBox.Show("文字認識エンジンを選択してください");
    }
}

文字の認識結果は、一つの候補だけではなく、複数の候補を取得できます。
今回は第一候補のみMessageBoxで表示し、第一候補を含む全ての文字列は出力に表示しています。

6. App.configの設定追加
ここで一旦アプリを実行してみると、環境によっては以下のような例外が発生し、アプリが強制終了します。

混合モード アセンブリはバージョン ‘v1.0.3705′ のランタイムに対して作成されており、追加の構成情報がないと 4.0 ランタイムでは読み込めません。

これは、使用しているアセンブリが.NET Frameworkのバージョン1.0.3705で作成したものを、.NET Framework 4のランタイムで動作させると発生する例外です。
対策としては、App.configにuseLegacyV2RuntimeActivationPolicyを追加する必要があります。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true"> 
        
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup>
</configuration>

再度、アプリケーションを実行すると、例外は発生しません。

以上で、文字認識の実装が完了しました。
実際に文字を書いて認識させてみましょう。

私の方では、Windows 7 Professional SP1で実行し、文字認識エンジンは「Microsoft 日本語手書き認識エンジン」を指定して文字を認識させています。

wpf_03_00

以上で、WPFのインク機能についての紹介は終了です。
次回からはWindowsフォームアプリケーションの話に入ります。

サンプルソースはこちらにアップしてありますので、興味のある方は実際に試して頂ければと思います。

Top