Introduction

Windows 10 に OCR 機能が組み込まれているので、それを試してみたが、言語パックだ Windows Runtime (WinRT) だと色々あったのでまとめた。

サンプルソースは、GitHub に下記を用意しました

サンプルは .NET Framework 4.8 のコンソールアプリケーションです。

How to use?

コーディング前に準備が必要だったりします。

Windows メタデータ の参照

OCR は WinRT として実装、提供されているため、Windows メタデータの参照が必要。

Winmd

nuget パッケージのインストール

WinRT の各種機能を呼び出すには nuget パッケージ Microsoft.Windows.SDK.Contracts を利用するのが最速。
参照した Windows メタデータと同じバージョンを利用するが安全だと思われる。

nuget

コード

シンプルなコードで、ログ出力、処理速度出力をしています。
また、認識に使用する OCR の言語を引数で変更できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Media.Ocr;

using NLog;

namespace Demo
{

internal sealed class Program
{

#region Fields

private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

private static readonly Stopwatch Stopwatch = new Stopwatch();

#endregion

#region Methods

private static void Main(string[] args)
{
if (args.Length != 2)
{
Logger.Error($"{nameof(Demo)} <languageTag> <image file path>");
return;
}

// Setup ocr engine
var languageTag = args[0];
if (!TrySetupOcrEngine(languageTag, out var ocrEngine))
return;

// Read image binary
var path = args[1];
var image = GetImageBinary(path);
if (image == null)
return;

// Convert to SoftwareBitmap
var bitmap = ConvertToSoftwareBitmap(image).Result;
if (bitmap == null)
return;

// Run ocr and display result
RunOcr(ocrEngine, bitmap);
}

#region Helpers

private static async Task<SoftwareBitmap> ConvertToSoftwareBitmap(byte[] image)
{
Stopwatch.Restart();

try
{
using (var memoryStream = new MemoryStream(image))
using (var randomAccessStream = memoryStream.AsRandomAccessStream())
{
var decoder = await BitmapDecoder.CreateAsync(randomAccessStream);
return await decoder.GetSoftwareBitmapAsync();
}
}
catch (Exception e)
{
Logger.Error(e, "Failed to convert to SoftwareBitmap");
return null;
}
finally
{
var ms = Stopwatch.ElapsedMilliseconds;
Logger.Info($"{nameof(ConvertToSoftwareBitmap)}: {ms} ms");
}
}

private static byte[] GetImageBinary(string path)
{
Stopwatch.Restart();

try
{
return File.ReadAllBytes(path);
}
catch (Exception e)
{
Logger.Error(e, "Failed to get image file binary");
return null;
}
finally
{
var ms = Stopwatch.ElapsedMilliseconds;
Logger.Info($"{nameof(GetImageBinary)}: {ms} ms");
}
}

private static void RunOcr(OcrEngine ocrEngine, SoftwareBitmap bitmap)
{
Stopwatch.Restart();

try
{
var task = ocrEngine.RecognizeAsync(bitmap).AsTask();
task.Wait();
Stopwatch.Stop();

var text = task.Result.Text;
Logger.Info($"Result: {text}");
}
catch (Exception e)
{
Logger.Error(e, "Failed to run ocr");
}
finally
{
var ms = Stopwatch.ElapsedMilliseconds;
Logger.Info($"{nameof(RunOcr)}: {ms} ms");
}
}

private static bool TrySetupOcrEngine(string languageTag, out OcrEngine engine)
{
Stopwatch.Restart();

engine = null;

try
{
var language = new Windows.Globalization.Language(languageTag);

// https://docs.microsoft.com/en-us/uwp/api/windows.media.ocr.ocrengine.trycreatefromlanguage?view=winrt-22621
engine = OcrEngine.TryCreateFromLanguage(language);
if (engine == null)
{
Logger.Error("Failed to create ocr engine because it could be lack of language pack.");
return false;
}

return true;
}
catch (Exception e)
{
Logger.Error(e, "Failed to create ocr engine");
return false;
}
finally
{
var ms = Stopwatch.ElapsedMilliseconds;
Logger.Info($"{nameof(TrySetupOcrEngine)}: {ms} ms");
}
}

#endregion

#endregion

}

}

認識結果

後述しますが、言語パックの有無で認識精度が変化します。
正しくは、認識させたいテキストの言語に応じた OCR エンジンを生成する必要があるということです。

例えば、下記の画像を日本語の OCR エンジンで認識させます。

testdata

1
2
3
4
5
6
$ sources\Demo\bin\Release\Demo.exe ja testdata\ja.png
2022-06-04 22:51:54.4947 [INFO ] TrySetupOcrEngine: 2 ms
2022-06-04 22:51:54.5227 [INFO ] GetImageBinary: 0 ms
2022-06-04 22:51:54.5584 [INFO ] ConvertToSoftwareBitmap: 28 ms
2022-06-04 22:51:54.7014 [INFO ] Result: 昭 和 ニ 十 - 年 憲 法 日 本 国 憲 法 日 本 国 民 は 、 正 当 に 選 挙 さ れ た 国 会 に お け る 代 表 者 を 通 し て 行 動 し 、 わ れ ら と わ れ ら の 子 孫 の た め に 、 諸 国 民 と の 協 和 に よ る 成 果 と 、 わ が 国 全 土 に わ た っ て 自 由 の も た ら す 恵 沢 を 確 保 し 、 政 府 の 行 為 に よ っ て 再 び 戦 争 の 惨 禍 が 起 る こ と の な い や う に す る こ と を 決 意 し 、 こ こ に 主 権 が 国 民 に 存 す る こ と を 目 言 し 、 こ の 法 を 確 定 す る 。 そ も そ も 国 政 は 、 国 民 の 廠 粛 な 信 託 に よ る も の で あ っ て 、 そ の 権 威 は 国 民 に 由 来 し 、 そ の 権 力 は 国 民 の 代 表 者 が こ れ を 行 使 し 、 そ の 福 利 は 国 民 が こ れ を 享 受 す る 。 こ れ は 人 類 普 遍 の 原 理 で あ り 、 こ の 法 は 、 か か る 原 理 に 基 く も の で あ る 。 わ れ ら は 、 こ れ に 反 す る - 切 の 法 、 法 令 及 び 詔 勅 を 排 除 す る 。 日 本 国 民 は 、 恒 久 の 平 和 を 念 願 し 、 人 間 相 互 の 閂 係 を 支 配 す る 崇 高 な 理 想 を 深 く 自 覚 す る の で あ っ て 、 平 和 を 愛 す る 諸 国 民 の 公 正 と 信 義 に 信 頼 し て 、 わ れ ら の 安 全 と 生 存 を 保 持 し よ う と 決 意 し た 。 わ れ ら は 、 平 和 を 維 持 し 、 専 制 と 隷 従 、 圧 迫 と 偏 狭 を 地 上 か ら 永 遠 に 除 去 し よ う と 努 め て ゐ る 国 社 会 に お い て 、 名 誉 あ る 地 位 を 占 め た い と 思 ふ 。 わ れ ら は 、 全 世 界 の 国 民 が 、 ひ と し く 恐 怖 と 欠 乏 か ら 免 か れ 、 平 和 の う ち に 生 存 す る 権 利 を 有 す る こ と を 確 認 す る 。 わ れ ら は 、 い づ れ の 国 家 も 、 自 国 の こ と の み に 等 念 し て 他 国 を 無 視 し て は な ら な い の で あ っ て 、 政 治 道 徳 の 法 則 は 、 普 遍 的 な も の で あ り 、 こ の 法 則 に 従 ふ こ と は 、 自 国 の 主 権 を 維 持 し 、 他 国 と 対 等 閂 係 に 立 た う と す る 各 国 の き 務 で あ る と 信 す る 。 日 本 国 民 は 、 国 家 の 名 誉 に か け 、 全 力 を あ け て こ の 崇 高 な 理 想 と 目 的 を 達 成 す る こ と を ふ 。
2022-06-04 22:51:54.7014 [INFO ] RunOcr: 141 ms

多少誤字はあるものの良好な結果です。

英語のテキストを認識出来るか?

下記の画像のような英文です。

testdata

日本語の OCR エンジンにかけますが、あまり良くない結果です。

1
2
3
4
5
6
$ sources\Demo\bin\Release\Demo.exe ja testdata\en.png
2022-06-04 23:07:14.7779 [INFO ] TrySetupOcrEngine: 2 ms
2022-06-04 23:07:14.8040 [INFO ] GetImageBinary: 0 ms
2022-06-04 23:07:14.8375 [INFO ] ConvertToSoftwareBitmap: 29 ms
2022-06-04 23:07:14.9762 [INFO ] Result: " The Constitution Of the United states Of America ( 1787 ) (See Note 1 ) Wethe People ofthe united States ′ in 0 「 de 「 t0f0n11 a more perfect Union, establishJustice, insure domesticTranquility, provideforthe common defence, promotethe general Welfare, and secu 「 e the Blessings of Liberty to ou 「 se ⅳ es and ou 「 Posterity, do ordain and establish this Constitution 「 0 「 the United States 0 「 America. Sectlon 1. Alllegislative Powers he 「 ein granted shall be vested in a Congress 0 「 the United States, which shall consist Of a Senate and House Of Representatives.
2022-06-04 23:07:14.9772 [INFO ] RunOcr: 137 ms

英語のテキストを認識させよう

ということで、言語指定を en にしますが

1
2
3
$ sources\Demo\bin\Release\Demo.exe en testdata\en.png
2022-06-04 23:01:11.8062 [ERROR] Failed to create ocr engine because it could be lack of language pack.
2022-06-04 23:01:11.8357 [INFO ] TrySetupOcrEngine: 31 ms

OCR エンジンが生成できません。
これは、指定した言語の OCR エンジンが OS にインストールされていないため、OcrEngine.TryCreateFromLanguage が null を返すためです。

任意の言語に対応した OCR エンジンを追加するには OS の言語設定から言語パックを追加する必要があります。

language-pack-install

language-pack-install

language-pack-install

光学式文字認識 という文字が見えます。

これをインストールすれば OK。
再起動も不要。

再度挑戦。

1
2
3
4
5
6
$ sources\Demo\bin\Release\Demo.exe en testdata\en.png
2022-06-04 23:05:57.2636 [INFO ] TrySetupOcrEngine: 5 ms
2022-06-04 23:05:57.2906 [INFO ] GetImageBinary: 0 ms
2022-06-04 23:05:57.3296 [INFO ] ConvertToSoftwareBitmap: 34 ms
2022-06-04 23:05:57.3826 [INFO ] Result: The Constitution of the United States of America (1787) (See Note 1) We the People of the united States, in Order to form a more perfect Union, establish Justice, insure domestic Tranquility, provide for the common defence, promote the general Welfare, and secure the Blessings of Liberty to ourselves and our Posterity, do ordain and establish this Constitution for the United States of America. Section 1. All legislative Powers herein granted shall be vested in a Congress of the United States, which shall consist of a Senate and House of Representatives.
2022-06-04 23:05:57.3826 [INFO ] RunOcr: 50 ms

劇的に改善しました。
おまけに認識速度も改善です。

Source Code

https://github.com/takuya-takeuchi/Demo/tree/master/ComputerVision/03_Windows10_OCR_DotNetFramework