Help us understand the problem. What is going on with this article?

画面を文字認識(OCR)してみよう!(C#.NET on Windows10)

はじめに

Windows10でOCRをする方法は

  1. 自分で実装する
  2. クラウドサービスを使う(AWS,GCP,Azureなど)
  3. Tesseractを使う
  4. Windows10搭載のMicrosoftOCRを使う

大体以上の4つがあります。
今回は主に④のMicrosoftOCRを使いながら、
C#.NETで画面の文字を認識を試みてみます。

なお、この記事は"公開型開発プロジェクト"PRODUCTICAの過程で作られた記事です。
ご興味がある方はTwitterの公式アカウントを是非ご覧になってみてください!
https://twitter.com/Productica_lis

使用するもの

  • Microsoft VisualStudio 2019
  • Microsoft Windows10 Software Development Kit

MicrosoftOCRについて

MicrosoftOCRは、デスクトップ版Windows10に実装されている
Optical Character Recognition(OCR)・文字認識用APIです。

様々なOCRの中でも結構精度が高いらしいです。
https://rpa.bigtreetc.com/column/microsoftocr/

使い方についてですが、
プロジェクトをUWP形式かWPF形式で作るかによって使い方が違います。

・UWPの場合
using Windows.Media.Ocr;を書くことでそのままで使うことが出来る。

・UWP以外の場合(WPFやFormsなど)
NuGetでMicrosoft.Windows.SDK.Contractsプラグインを導入する必要がある。
また、それに伴った複数の設定が必要。

以下、WPF形式でプラグインを導入して使う方法を説明していきます。

Windos.SDK.Contractsプラグインの導入

Microsoft.Windows.SDK.ContractsはUniversalWindowsのAPIをWPFなどのプロジェクトで使うことが出来るようにするプラグインです。導入することでUWP形式で使えるWindows10の標準APIを使うことができます。

導入するためには、VisualStudio上で以下の手順を行ってください。

1. [ツール]>[NuGetパッケージマネージャー]>[パッケージマネージャー設定]を開く。

2. [パッケージの管理]にある[既定のパッケージ管理形式]を
「PackageReference」に変更する(※1)

3. プロジェクトを作る(※2)

4. [NuGetパッケージの管理] を開く。

5. 検索ボックスの右側にある [プレリリースを含める] にチェックを入れる。

6. 検索ボックスに「Microsoft.Windows.SDK.Contracts」と入力して検索する。

7. 「Microsoft.Windows.SDK.Contracts」を選択し、インストールする(※3)。

8. 下記のURLよりContractsのバージョンに合うWindows10SDKをインストールする。
 過去バージョンのSDK
  https://developer.microsoft.com/ja-jp/windows/downloads/sdk-archive/
 最新バージョンのSDK
  https://developer.microsoft.com/ja-jp/windows/downloads/windows-10-sdk/

13. [参照の追加] を開く。

14. [参照(B)] ボタンを選択し、ファイル選択ダイアログを表示する。

15. 下記のファイルをそれぞれ設定(sdk-versionは任意のバージョン)(※4)
 ・System.Runtime.WindowsRuntime
  C:\Windows\Microsoft.NET\Framework\v4.0.30319
 ・System.Runtime.WindowsRuntime.UI.Xaml
  C:\Windows\Microsoft.NET\Framework\v4.0.30319
 ・System.Runtime.InteropServices.WindowsRuntime
  C:\Windows\Microsoft.NET\Framework\v4.0.30319
 ・windows.winmd
  C:\Program Files (x86)\Windows Kits\10\UnionMetadata\<sdk version>\Facade
 ・Windows.Foundation.UniversalApiContract.winmd
  C:\Program Files (x86)\Windows Kits\10\References\<sdk version>\Windows.Foundation.UniversalApiContract
 ・Windows.Foundation.FoundationContract.winmd
  C:\Program Files (x86)\Windows Kits\10\References\<sdk version>\Windows.Foundation.FoundationContract

※1.パッケージ管理システムがPackage.configだと導入時にエラーが出る場合がある。
※2.既存のプロジェクトを開く場合、パッケージ管理がPackage.configのままの場合があるので、ソリューションエクスプローラー内の参照ツリーを右クリックし、[Package.configをPackageReferenceに移行する]があればそれを押す。その後、プラグインなどの確認ウインドウが出るので問題がなければOKを押す。
※3.バージョンは幾つかあるので、使用したい・インストール済みのWindowsSDKのバージョンと合わせる。
※4.参照の追加によって競合が発生する場合があります。その場合はエラーに基づいて一部追加した参照を消してください。

画面をキャプチャする

以下のコードを使い画面全体のキャプチャを取得する。

using System.Drawing;
using System.Windows.Forms;
private Bitmap CaptureScreen(){
    //Bitmapの作成
    Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
    Screen.PrimaryScreen.Bounds.Height);
    //Graphicsの作成
    Graphics g = Graphics.FromImage(bitmap);
    //画面全体をコピーする
    g.CopyFromScreen(new Point(0, 0), new Point(0, 0), bmp.Size);
    //解放
    g.Dispose();
    return bitmap;
}

BitmapをSoftwareBitmapに変換

上記で画面の画像は取得できるが、このままではMicrosoftOCRでは処理できません。
何故なら、MicrosoftOCRのインプットはSoftwareBitmapという形式になっているからです。
そのため、取得したBitmapを以下のコードでSoftwareBitmapに変換します。

using System.IO;
//using System.Drawing;ダブリ、単体で使う場合は有効に
using System.Drawing.Imaging;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.Graphics.Imaging;
public async Task<SoftwareBitmap> GetSoftwareSnapShot(Bitmap snap)
{
    // 取得したキャプチャ画像をファイルとして保存
    var folder = Directory.GetCurrentDirectory();
    var imageName = "ScreenCapture.bmp";
    StorageFolder appFolder = await StorageFolder.GetFolderFromPathAsync(@folder);
    snap.Save(folder + "\\" + imageName, ImageFormat.Bitmap);
    SoftwareBitmap softwareBitmap;
    var bmpFile = await appFolder.GetFileAsync(imageName);

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

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

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

一旦画像を保存して、それをsoftwareBitmap形式に読み込み直すという若干力技じみた実装ではあります。
他にスマートな方法もありそうなので、詳しい方は教えていただけると幸いです。

画像を文字認識する

ここはとっても簡単、OcrEngineを作ってSoftwareBitmapを渡すだけ。

using Windows.Media.Ocr;
//using Windows.Graphics.Imaging;ダブリ
private async Task<OcrResult> RecognizeText(SoftwareBitmap snap)
{
    OcrEngine ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages();
    // OCR実行
    var ocrResult = await ocrEngine.RecognizeAsync(snap);
    return ocrResult;
}

上記の出力結果ocrResult.textで認識結果(String)を得ることが出来ます。

おわりに

今回はWindows10 OCR APIを使いましたが、実装と検証に多くの時間が割けられるのならば、自分で1から実装することも良いと思います。そういう場合、機械学習を用いた文字認識モデルを作る手法などを考えたり実装することになります。Pythonではそれらの機械学習の実装が頻繁に行われているので、それらリソースを参照しながら各言語で実装を進めるのが良いかもしれません。

以下の記事が参考になりそうなので、貼っておきます。
【日本語OCRを作ったので解説してみる】
https://qiita.com/tanreinama/items/8fc1c8af6554654aae00
【文字認識アルゴリズムのFOTSを実装した】
https://qiita.com/jjjkkkjjj/items/bfa03d89eaf6ab0c0487#recognition

hs-lis
細々と生きています
link_information_systems
放送・航空宇宙・商社・自動車・通信・防災・データセンター・社会インフラなど広範囲な分野で、ソフトウエア開発からシステム運用まで、またテレビの字幕制作など幅広いサービスを提供しています。
https://www.lis.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away