1. Yukio-Ichikawa

    Posted

    Yukio-Ichikawa
Changes in title
+Windows Native C++でWinRTのOCR APIを使う方法
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,101 @@
+# はじめに
+
+こんにちは。Daddy's Officeの市川です。
+
+私が10年以上開発を続けているWindowsPCを監視カメラシステムにする「LiveCapture3」。
+先日、このソフトにOCR機能を追加して、カメラ映像内の数値を検出できるようにしました。
+(この機能により、サーマルカメラを使用した自動温度計測&通知システムの構築が可能です)
+
+「LiveCapture3」のコア機能はC++で実装しているので、C++でOCR機能を実装する必要がありました。
+C++でのOCRといえば、「[Tesseract][1]」が有名ですが、今回は画像内の数値のみ検出すればよく、そこまで大掛かりにしたくありませんでした。
+
+そこでWindowsのAPIを調べたところ、ありました!
+[Windows.Media.Ocr][2]
+
+しかし、よくよく見てみると、これは[WinRT][3]っぽい感じ。
+つまり、UWPアプリやストアアプリであれば使えるのですが、デスクトップアプリから使うにはちょっと細工が必要そうです。
+
+ということで
+
+- WinRTのWindows.Media.Ocrを.NetFrameworkのC#で使えるようにする
+- 上記のC# .NetFrameworkモジュールをC++から使えるようにする
+
+という2段階で実装しました。
+
+# WinRTのWindows.Media.Ocrを.NetFrameworkで使う
+
+言語としてはどちらもC#なので、参照を追加できれば基本はOKです。
+
+まず、.NetFrameworkのクラスライブラリとしてプロジェクトを生成します。
+
+OCRを使用する為には、下記のUWPライブラリが必要です。
+
+ - Windows.Media.Ocr
+ - Windows.Storage.Streams
+ - Windows.Graphics.Imaging
+
+これらを使えるようにするために、プロジェクトの参照で、直接ライブラリを追加します。
+![参照.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382663/868376bf-78b2-3d4e-3208-8e3fa10e0cf9.jpeg)
+
+追加するのは下記の2つです。
+
+| 名前 |パス|
+|:-:|:-:|
+|Windows.Foundation.UniversalApiContract|C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.UniversalApiContract\8.0.0.0\Windows.Foundation.UniversalApiContract.winmd|
+|Windows.Foundation.FoundationContract|C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd|
+
+これで、準備はできました。
+
+OCRエンジンの使い方は非常に簡単で、画像を渡すと認識結果の文字列が返却されるというものです。
+
+```C#
+using Windows.Graphics.Imaging;
+using Windows.Media.Ocr;
+using Windows.Storage.Streams;
+
+async Task<OcrResult> detect(SoftwareBitmap bitmap)
+{
+ var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages();
+ var ocrResult = await ocrEngine.RecognizeAsync(bitmap);
+ return ocrResult;
+}
+```
+
+ただ、面倒くさいのが
+
+- 引数の画像はSoftwareBitmap(WinRT)を使う必要がある
+- WinRTのAsyncは、デスクトップのasync/awaitとは違う形式になっている
+
+というところを解決しないといけません。
+
+色々調べた結果、以下に素晴らしい説明がありました!
+
+[Microsoft OCR をデスクトップのWFPアプリで動かす方法][4]
+
+参照追加の方法がちょっと違いますが、実装コードはこのまま行けました!
+
+# .NetFrameworkライブラリをC++からコールする
+
+これは、以前私が投稿した下記のやり方で行います。
+
+[既存のC++ネイティブプロジェクトでC#マネージドコードを使う][5]
+
+これで、Native C++からWinRT用のOCR APIをコールしてOCR機能を実現することができました!
+
+# ソースコード
+
+ソースコード一式(VisualStudio2019)はこちらに置いておきます。
+
+[ソースコード一式][6]
+
+#参考
+[Microsoft OCR をデスクトップのWFPアプリで動かす方法][4]
+[既存のC++ネイティブプロジェクトでC#マネージドコードを使う][5]
+
+[1]:https://ja.wikipedia.org/wiki/Tesseract_(ソフトウェア)
+[2]:https://docs.microsoft.com/en-us/uwp/api/Windows.Media.Ocr?view=winrt-19041
+[3]:https://ja.wikipedia.org/wiki/Windowsランタイム
+[4]:https://www.moonmile.net/blog/archives/8584
+[5]:https://qiita.com/Yukio-Ichikawa/items/f1a15dfda18bf8748268
+[6]:https://github.com/daddyYukio/WindowsOCR/tree/master
+