C#/WinRT で OCR やってみた


試してみたが、精度は微妙・・・?

環境について

WinRTはデフォルトだと入ってないので、インストールが必要です。
Windows8以上が必要で Visual Studioのオプションだったはず。。(忘れました。。。)

実行結果

入力画像

出力結果

コンパイルバッチ

ダブルクオートつかった行は 「^」 で改行つなげないようなので1行にまとめた。

compile.bat

csc /r:C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Runtime.WindowsRuntime\v4.0_4.0.0.0__b77a5c561934e089\system.runtime.windowsruntime.dll ^
/r:C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Runtime.InteropServices.WindowsRuntime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.InteropServices.WindowsRuntime.dll ^
/r:C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Runtime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.dll ^
/r:C:\Windows\Microsoft.NET\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll ^
/r:C:\Windows\Microsoft.NET\assembly\GAC_64\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll ^
"/r:C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.UniversalApiContract\8.0.0.0\Windows.Foundation.UniversalApiContract.winmd" "/r:C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd" %*

ソースコード

コマンドライン引数で渡された画像ファイルから文字列を認識してコンソールに出力します。


using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Media.Ocr;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.Foundation;


class OcrTest
{
    [System.STAThread]
    static void Main(string[] args)
    {
        if(args.Length==0){return;}
        Task<string> ret = LoadImageAndOcr(args[0]);
        Console.WriteLine(ret.Result);
    }

    static async Task<OcrResult> detect(SoftwareBitmap bitmap)
    {
        var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages();
        var ocrResult = await MyWaitUtil<OcrResult>.GetResultWithWaiting( ocrEngine.RecognizeAsync(bitmap) );
        // https://docs.microsoft.com/ja-jp/uwp/api/windows.media.ocr.ocrresult.lines?view=winrt-19041
        return ocrResult;
    }

    static async Task<string> LoadImageAndOcr(string path)
    {
        var inputFile = await MyWaitUtil<StorageFile>.GetResultWithWaiting(
            StorageFile.GetFileFromPathAsync( Path.GetFullPath(path) )
        );

        SoftwareBitmap softwareBitmap;
        // https://docs.microsoft.com/ja-jp/windows/uwp/audio-video-camera/imaging
        using (var stream = await MyWaitUtil<IRandomAccessStream>.GetResultWithWaiting(inputFile.OpenAsync(Windows.Storage.FileAccessMode.Read)))
        {
            // Create the decoder from the stream
            var decoder = await MyWaitUtil<BitmapDecoder>.GetResultWithWaiting(
                BitmapDecoder.CreateAsync(stream)
            );

            // Get the SoftwareBitmap representation of the file
            softwareBitmap = await MyWaitUtil<SoftwareBitmap>.GetResultWithWaiting((decoder.GetSoftwareBitmapAsync()));
        }

        OcrResult t = await detect(softwareBitmap);

        return t.Text;
    }
}

// IAsyncOperationのGetAwaiterがないとか謎のコンパイルエラーがでたので、その対策として実装した
public static class MyWaitUtil<T>
{
    public static async Task<T> GetResultWithWaiting(IAsyncOperation<T> task)
    {
        while(task.Status != AsyncStatus.Completed){
            if (task.Status == AsyncStatus.Error || task.Status == AsyncStatus.Canceled){
                Console.WriteLine("Error or Canceled");
                return default(T);
            }
            await Task.Delay(1);
        };
        return task.GetResults();
    }
}

参考サイト