SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

UWPアプリ開発の最前線

日本語OCRによる文字認識
~WPFなどの.NET FrameworkアプリやUWPアプリからWindows 10のOCRエンジンを使う

UWPアプリ開発の最前線 第4回


OCRエンジンの使い方(UWP編)

おおまかな流れ

 Windows 10のOCRエンジンを使う処理のおおまかな流れは、次の図のようになります。

使える言語を確認し、SoftwareBitmap型で画像を取り込み、OCRエンジンを呼び出す
OCRエンジンを使うおおまかな流れ

 まず最初に、利用できる言語の一覧を取得します。これは、前述したように、読み取りたい文書に適した言語を指定しないと認識精度が落ちるからです。一覧を取得したら、必要な言語が使えることをコードで確認したり、一覧を提示してそこからユーザーに選択してもらったりします。

 次に、認識させたい画像を取り込みます。このとき、SoftwareBitmapクラス(Windows.Graphics.Imaging名前空間)のオブジェクトにしなければなりません。UWPアプリでは特に問題ありませんが、WPFなどの.NET Frameworkアプリではちょっと手間です(後述)。

 OCRエンジンの呼び出し自体は簡単です。言語を指定してOcrEngineクラス(Windows.Media.Ocr名前空間)のインスタンスを作り、RecognizeAsyncメソッドに画像を渡すだけです。

サポート言語の一覧を取得する

 利用できる言語の一覧を取得するには、OcrEngineクラスのAvailableRecognizerLanguages静的プロパティを見ます。これが、利用できる言語を表すLanguageクラス(Windows.Globalization名前空間)のコレクションになっています。

 また、現在のユーザー設定に基づく言語を取得することもできます。OcrEngineクラスのTryCreateFromUserProfileLanguages静的メソッドを呼び出すと、ユーザーのプロファイルに基づいたOcrEngineインスタンスが生成されます。そのRecognizerLanguageプロパティ(Language型)が、(OCRエンジンにとっての)現在のユーザーの言語です。これは、ユーザーがWindowsの「設定アプリ」で設定している言語と同じとは限りません。英語以外の言語の場合、OCRエンジンのサポートがあるとは限りませんし、また、サポートされていてもそのランゲージパックがインストールされている必要があるからです。

 例として、利用できる言語の一覧を取得してコンボボックスに表示し、さらにユーザーの言語を選択状態にするC#のコードは、次のようになります(MainPage.xaml.csのsetLanguageListローカル関数)。

サポート言語の一覧をコンボボックスに表示する例
// サポート言語の一覧を得る
IReadOnlyList<Language> langList = OcrEngine.AvailableRecognizerLanguages;

// コンボボックス「LangComboBox」にサポート言語の一覧を表示する
this.LangComboBox.ItemsSource = langList;
// 選択肢として表示するのはDisplayNameプロパティ(「日本語」など)
this.LangComboBox.DisplayMemberPath = nameof(Windows.Globalization.Language.DisplayName);
// SelectedValueとしてLanguageTagプロパティを使う(「ja」など)
this.LangComboBox.SelectedValuePath = nameof(Windows.Globalization.Language.LanguageTag);

// ユーザープロファイルに基いてOCRエンジンを作る
var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages();
// その認識言語をコンボボックスで選択状態にする
this.LangComboBox.SelectedValue = ocrEngine.RecognizerLanguage.LanguageTag;

 言語を1つも追加していない日本語版Windows 10で実行してみると、コンボボックスには日本語と英語(en-us)が表示されます(次の画像)。英語だけは、ランゲージパックの導入に関係なく、常に利用できるようです。

ランゲージパック未追加環境でも英語は選択できる
ランゲージパック未追加(WPFアプリ)
後ろに写っている「設定アプリ」で既定の日本語環境だけと分かりますが、英語も選択できます

 そのほかの言語は、ランゲージパックを導入すると利用可能になります。次の画像は、中国語(zh-Hans-CN)のランゲージパックがインストールされている状態です。

中国語ランゲージパックを導入した環境では中国語も選択できる
ランゲージパック追加後(UWPアプリ)
後ろに写っている「設定アプリ」で英語と中国語のランゲージパックが導入済みだと分かります

画像を取り込んでSoftwareBitmap型にする

 OCRエンジンが認識できる画像データはSoftwareBitmap型だけです。UWPアプリで画像ファイルやクリップボードの画像データを認識させるには、そのストリームから次のコードのようにしてBitmapDecoderクラス(Windows.Graphics.Imaging 名前空間)を使ってSoftwareBitmapオブジェクトを作ります(⇒SoftwareBitmapHelper.cs)。画像をImageコントロールに表示もしたいときは、Imageコントロールが受け付けてくれる画像フォーマットにしておく必要があります(BGRA8形式でアルファチャネルはプリマルチプライ処理済み)。

画像データのストリームからImageコントロールに表示可能なSoftwareBitmapオブジェクトを作るメソッド
// 画像データのストリームからSoftwareBitmapを作る
public static async Task<SoftwareBitmap> ConvertToSoftwareBitmap(IRandomAccessStream stream)
{
  BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
  return await decoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Bgra8,
                                              BitmapAlphaMode.Premultiplied);
}

 また、MediaCaptureクラス(Windows.Media.Capture 名前空間)を使ってWebカメラから静止画をキャプチャするときも、それをImageコントロールに表示するなら、次のコードのようにしてSoftwareBitmapオブジェクトの画像フォーマットを修正する必要があります。筆者の手元の環境では、MediaCaptureオブジェクトが返してきたSoftwareBitmapオブジェクトは、BGRA8形式ではありましたがアルファチャネルはストレート(アン・プリマルチプライド)でした。

SoftwareBitmapをImageコントロールに表示可能な画像フォーマットに作り直すメソッド
// SoftwareBitmapの画像フォーマットをImageコントロールに表示できるものに作り直す
public static SoftwareBitmap CorrectFormat(SoftwareBitmap bitmap)
{
  if (bitmap.BitmapPixelFormat != BitmapPixelFormat.Bgra8
        || bitmap.BitmapAlphaMode == BitmapAlphaMode.Straight)
  {
    // Imageコントロールに表示できるのは、BGRA8形式でアルファはプリマルチプライド
    var newBitmap = SoftwareBitmap.Convert(bitmap, BitmapPixelFormat.Bgra8,
                                           BitmapAlphaMode.Premultiplied);
    bitmap.Dispose();
    return newBitmap;
  }
  return bitmap;
}

OCRエンジンを呼び出す

 OCRに認識させる言語を決定し、SoftwareBitmapオブジェクトの準備ができたら、次のコードのようにしてOCRエンジンのインスタンスを作ってRecognizeAsyncメソッドを呼び出すだけです(⇒MainPage.Ocr.csのRecognizeBitmapAsyncメソッド内)。OcrEngineクラスのTryCreateFromLanguageメソッドに渡すLanguageオブジェクトとして、ここでは前述のコンボボックスで選択されたものを使っています。

OCRエンジンに画像認識させるコード
// 言語を指定してOCRエンジンのインスタンスを作る
var ocrEngine
  = OcrEngine.TryCreateFromLanguage(this.LangComboBox.SelectedItem as Language);

// OCRエンジンにSoftwareBitmapオブジェクトを渡して文字認識させる
OcrResult ocrResult = await ocrEngine.RecognizeAsync(bitmap);

 なお、OCRエンジンが処理できる画像サイズには限度があります。今回のサンプルコードでは割愛しましたが、必要なときはOcrEngineクラスのMaxImageDimension静的プロパティを参照してください(筆者の手元の環境では1万ピクセルでした)。

次のページ
OCRエンジンの使い方(WPF編)

この記事は参考になりましたか?

UWPアプリ開発の最前線連載記事一覧

もっと読む

この記事の著者

biac(ばいあっく)

HONDA R&Dで自動車の設計をやっていた機械屋さんが、技術の進化スピードに魅かれてプログラマーに。以来30年ほど、より良いコードをどうやったら作れるか、模索の人生。わんくま同盟の勉強会(名古屋)で、よく喋ってたりする。2014/10~2019/6 Microsoft MVP (Windows Devel...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/10748 2019/11/10 20:59

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー