かくすけのいろいろ作るブログ

かくすけの開発者ブログです。開発の他いろいろなモノづくりについて書きます。

【C#】Windows10のOCRを使用する

Visual Studio 2019 C#

こんにちは。かくすけです。
前回、アプリの進捗を報告しました。

kakusuke98.hatenablog.com

画像をキャプチャし、文字認識、翻訳をするところまで作ったわけですが・・・
お金が気になる~~~
なんてったって、今の状態だと
・文字認識API呼び出し用のGateway(Amazon API Gateway)
・文字認識API呼び出し(AWS Lambda)
・文字認識(Google Cloud Vision API)
・翻訳API呼び出し用のGateway(Amazon API Gateway)
・翻訳API呼び出し(AWS Lambda)
・翻訳(Google Cloud Translation API)

という6工程において課金が発生するのです。
うーん。ただでさえ最近収入が減ったのにこれは苦しい。

翻訳は仕方ないとして、せめて文字認識だけでも無料で何とかしたい・・!
それができれば、いずれは「常に文字の変化を監視し、変化したら翻訳をする」といったことも可能になるかもしれません!
私が自動的にではなく手動で翻訳する方向性で考えているのは、少しでも課金を抑えようという考えからですからね。

調べました。
そして知りました。Windows10にはOCRエンジンが標準で搭載されていることを。

codezine.jp

先に調べるべきでした!!!
では、開発中のアプリからWindows10のOCRを使えるようにします。

目次

  • Windows SDKを参照する
  • SoftwareBitmap画像の準備
  • Windows10 の 搭載 OCR を使って画像内文字列を取得する
  • Windows10 の 搭載 OCR 注意点
  • Google Cloud Vision API と Windows10 の 搭載 OCR の比較
    • 価格
    • 精度
    • 速度
  • 使ってみて

Windows SDKを参照する

ここは躓きました。
別記事としてまとめたのでそちらを参考にしてくださいませ!

kakusuke98.hatenablog.com

SoftwareBitmap画像の準備

では、実際に Windows10 のOCRを使用します。
その前に下の記事で書いた画面キャプチャ部分のソースコードも修正しなければなりません。

kakusuke98.hatenablog.com

前の記事ではBitmap形式で画面キャプチャを取得したのですが、Windows10のOCRではSoftwareBitmapという形式で画像を渡さなければいけないのです。
そのくらい簡単にSoftwareBitmap形式でとれるでしょ~♪と軽く見ていましたが全然情報がない・・
仕方なくBitmapで取得したものをSoftwareBitmapに変換する方式に方向転換しました。
しかし変換も簡単にはできないようで・・・

Bitmapとして取得した画像をファイルとして保存し、それをSoftwareBitmap形式で読み込む

という方法をとることにしました。
まわりくどいよ~。ほかに良い方法をご存じの方がいらっしゃったら教えてくださいまし。
画像の保存場所は実行ファイルが配置されている場所。一時的に使うファイルなのですぐに消してます。

        // SoftwareBitmapのスクリーンキャプチャ取得
        public async Task<SoftwareBitmap> GetSoftwareSnapShot()
        {
            // 画面のスクリーンキャプチャをBitmapとして取得(このメソッドは上の記事で作成したもの)
            Bitmap snap = await this.GetSnapShot();

            // 上で取得したキャプチャ画像をファイルとして保存
            var folder = Directory.GetCurrentDirectory();
            var image_name = "ScreenCapture.png";
            StorageFolder appFolder = await StorageFolder.GetFolderFromPathAsync(@folder);
            snap.Save(folder + "\\" + image_name, System.Drawing.Imaging.ImageFormat.Png);
            SoftwareBitmap softwareBitmap;
            var bmpFile = await appFolder.GetFileAsync(image_name);

            // 保存した画像をSoftwareBitmap形式で読み込み
            using (IRandomAccessStream stream = await bmpFile.OpenAsync(FileAccessMode.Read))
            {
                BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
                softwareBitmap = await decoder.GetSoftwareBitmapAsync();
            }

            // 保存した画像ファイルの削除
            File.Delete(folder + "\\" + image_name);

            // SoftwareBitmap形式の画像を返す
            return softwareBitmap;
        }

参考にさせていただいたページ

作業フォルダのパス取得
www.atmarkit.co.jp

Bitmapからの画像ファイル保存
dobon.net

SoftwareBitmap形式での画像読み込み
docs.microsoft.com

Windows10 の 搭載 OCR を使って画像内文字列を取得する

いよいよOCRを使います! メソッドはこちら

// 取得した画像のテキストを抽出する(Windows10 OCR)
// snap: 文字取得させたいSoftwareBitmap
async Task<OcrResult> RunWin10Ocr(SoftwareBitmap snap)
{
    // OCRの準備。言語設定を英語にする
    Windows.Globalization.Language language = new Windows.Globalization.Language("en");
    OcrEngine ocrEngine = OcrEngine.TryCreateFromLanguage(language);

    // OCRをはしらせる
    var ocrResult = await ocrEngine.RecognizeAsync(snap);
    return ocrResult;
}

呼び出しは↓みたいな感じで行います。

OcrResult ocrResult = await RunWin10Ocr(softwareSnap);  // softwareSnapはSoftwareBitmap形式の画像
string ocrText = ocrResult.Text;   // OCR結果文字列

↓のソースコードを参考にさせていただきました。

Windows 10 組み込みのOCRを利用するサンプル。UWP の Windows.Media.Ocr が OCR に関するクラス。 · GitHub

Windows10 の 搭載 OCR 注意点

今回は英語を指定してOCRを走らせているのですが、Windows Updateの項目から英語の言語パックをインストールする必要がありました
つまり人に使ってもらうためにはその人のWindows10に言語パックをインストールしてもらう必要があるということ。
苦しいな~、、、個人的に何かソフトウェアをインストールするときに別の何かがインストールされるのは非常に嫌なイメージがあります。
その点Google Vision APIの方は利用者側は何も考えなくていいからいいですよね。かわりに私のお財布が犠牲になるんですけどね。。。

Google Cloud Vision API と Windows10 搭載OCR の比較

# Google Cloud Vision API Windows10 搭載OCR
価格 月に1,000回以上使うと課金が発生 無料
精度 高い 低め(文字の色で精度が変わる)
速度 遅い(おそらくネットワークを介するため) 速い
その他 利用者に言語パックをインストールしてもらう必要あり。
Windows10限定

価格

今回Windows10搭載のOCRを使おうと思ったきっかけは価格の問題なのでもちろんそちらの方が安いです。
ただし、Google Cloud Vision API も月に1,000回までは無料で呼び出せるので個人で使う分にはなかなかそれを超えることはないと思います。
今回のアプリはいつかは公開するつもりなのでこの課金が怖いんですよね。

ちなみにこの課金は↓のような価格になってます(2019/10/02 現在)
f:id:kakusuke98:20191002215609p:plain

しばらくは1,000回使われるごとに150円ほどの課金といったところですね。
安く感じますが。。ちりも積もればというやつです。
私のように自作APIからこのGoogle Cloud Vision API を呼ぶとなったらさらにお金はかかっちゃいますしね。

精度

精度は所感ではありますがGoogle Cloud Vision APIの方が高い気がします。
例えば、次のような画像を読ませてみたところ

f:id:kakusuke98:20191002215126p:plain

以下のような結果になりました。

Google Cloud Vision API

private void save As Images Too StripMenultem Cl ick (object sender, EventArgs e)
Ut ility.SaveAsImages (snaps);
/private void saveAsWordTool StripMenultem Click(object sender, Event Args e)
//Ut ility.SaveAs Wo rd (snaps) ;
//

Windows10 搭載OCR

saveAsImagesToolStripMenuItem_Cl ick(obj ect sender, Ut i lit y .SavegsImages(snaps); Eventgrgs e)

元画像がソースコードなのも精度比較用としてはどうかと思いますが(自分でやっておいて)、Windows10 搭載のOCR明度の差が少ない文字をほぼ認識しません。
黒背景に緑や青といった文字の部分は全然認識していません。
Windows10搭載のOCRを使用する場合には事前に画像加工を行った方がよさそうです。
また、変なところで次の行の認識を行ったりしています。1行目最後の "EventArgs e)"がなぜか最後に来てるんですよね。","を区切りとして扱っちゃってたりするんでしょうか。この問題は背景色に関係なく発生しました。

速度

速度は断然Windows10搭載のOCRの方が速いです。びっくりしました。
その比較がこちら。

Google Cloud Vision API
f:id:kakusuke98:20191002221036g:plain

Windows10 搭載OCR
f:id:kakusuke98:20191002221046g:plain

"取得範囲"列の"Name_1"が表示されてから"翻訳前"の列が読み込まれるまでの間が処理時間です。

・・・はやすぎません!?

確かにGoogle Cloud Vision APIの方は私の自作APIを介しているのでそこで時間がかかっているかもしれませんが。。この速度に慣れていたので初めてWindowsの方を使ったときはびっくりしました。
ネットワークを介さないとこんなにもOCRって素早く動くんですね!!!

ということで一長一短という印象です。
利用シーンにあわせて選択するのがいいんだろうなあ。

使ってみて

動くところまで開発したわけですが、やはり一長一短でどちらを使うかは悩むところです。

Windows10は利用者さんに言語パックをインストールしてもらう必要があるのですが、今回私がやったようにWindowsのコントロールパネルを開いて設定してもらわないといけないんであれば厳しいですね。
このアプリからボタンなどでさらっとインストールさせてあげられるのであれば、Windows10に搭載されているOCRを使いたいところです。
精度についてはきっと画像加工処理とかいれたらもっといい感じになるはず。

ひとまず開発した「Windows10 OCR 版」と「Google Cloud Vision API OCR 版」はいつでも切り替えられる状態にして、どうするかは後で考えることにします。
今回使わないことになっても、どちらもきっと別の場面で活用できるでしょう!