• ホーム
  • C#
  • C#でWindows10のOCRを使って文字認識する(WPF)

C#でWindows10のOCRを使って文字認識する(WPF)

C#のWPFアプリで、Windows10のOCR機能を使った文字認識をします。

目次

  1. Windows10にはOCR機能がある
  2. WPFアプリからWindows Runtime APIを呼び出す方法
    1. パッケージ管理方法の変更
    2. パッケージ参照の追加
  3. OCRの手順
  4. 実施例
    1. XAML
    2. コード
    3. 文字認識の例
  5. 主なメソッド
    1. WindowsRuntimeStreamExtensions.AsRandomAccessStream
    2. BitmapDecoder.CreateAsync
    3. BitmapDecoder.GetSoftwareBitmapAsync
    4. OcrEngine.TryCreateFromLanguage
    5. OcrEngine.RecognizeAsync

Windows10にはOCR機能がある

Windows10には、UWPアプリ用の機能としてOCRが備わっています。この機能はWindows Runtime APIを通して使用できます。

ということで、ここではWindows Runtimeの機能を利用して、画像から文字を読み取ってみます。

具体的には、UWPアプリ用のAPIであるWindows.Media.OcrをWPFアプリから呼び出して変換を行います。

WPFアプリからWindows Runtime APIを呼び出す方法

Microsoftの「デスクトップ アプリで Windows ランタイム API を呼び出す」という記事に手順が書かれています。

以下で実際に設定をしてみます。

パッケージ管理方法の変更

まず、Visual Studioのパッケージ参照の方法をPackageReferenceに変更します。

Visual Studioのメニューから、「ツール」→「NuGetパッケージマネージャー」→「パッケージマネージャー設定」の順に選択します。

パッケージマネジャーの設定

「オプション」ダイアログが開きますので、「NuGetパッケージマネージャー」の「全般」項目を選択して、「規定のパッケージ管理形式」を「PackageReference」に変更します。

オプションダイアログ

パッケージ参照の追加

パッケージ管理形式を変更したら、Visual Studioのメニューから「プロジェクト」→「NuGetパッケージの管理」を選択します。

パッケージマネージャー

NuGetパッケージ管理用のウィンドウが開きます。「参照」ページの検索欄にmicrosoft windows sdk contractsと入力して検索すると、Microsoft.Windows.SDK.Contractsというパッケージが見つかると思います。そうしたら「インストール」をクリックしてこのパッケージをインストールします。(下図はインストール済みの状態でのスクリーンショットなので、「インストール」のボタンに「アンインストール」と表示されてます。)

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

依存関係のある、System.Runtime.WindowsRuntimeとSystem.Runtime.WindowsRuntime.UI.Xamlも一緒にインストールされるはずです。もし自動的にインストールされない場合は、手動でインストールします。

特に今回はSystem.Runtime.WindowsRuntimeの機能を利用しますので、インストールされたかどうかよく確認してください。

以上で、Windows.Media.Ocrライブラリを使用する準備ができました。

OCRの手順

Windows.Media.Ocr.OcrEngineのインスタンスを作成して、そのインスタンスのRecognizeAsyncメソッドにSoftwareBitmap形式のデータを指定して実行すれば、OCRによる文字認識が実行されます。

とても分かり易いですね。

ただし、これをWPFアプリで実行すると面倒なことがあります。

SoftwareBitmapというのはUWPの世界の形式のため、WPFで使用されるBitmapSourceなどの形式からSoftwareBitmap形式に変換しなければいけないのです。

変換方法はいろいろあるのですが、ここではメモリストリームを使うことにします。

手順はこんな感じです。

  1. ファイルを読み込むなどしてBitmapSourceやWritableBitmapの画像データを準備する。

  2. 画像データをメモリストリームに書き出す。

  3. メモリストリームをRandomAccessStreamに変換する。

  4. RandomAccessStreamからSoftwareBitmapとして画像を読み込む。

  5. OcrEngineインスタンスを使ってOCRを実行する。

面倒ですが、仕方ありません。

実施例

下図の画像(当サイトのスクリーンショットの切り抜き)をPNGファイルとして保存したデータをOCRします。

アプリで読み込んだ画像を上部に表示して、その下部のTextBoxにOCRの結果を出力します。

サンプル画像

XAML

<Window x:Class="ocr_test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ocr_test"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="400" Loaded="Window_Loaded">
    <Grid>
        <StackPanel>
            <Image Name="imgSrc" Height="300" />
            <TextBox Name="txtResult" Height="100" Margin="10" TextWrapping="Wrap" />
        </StackPanel>
    </Grid>
</Window>

StackPanelにImageとTextBlockを並べただけですね。

コード

using System;
using System.IO;
using System.Windows;
using System.Windows.Media.Imaging;
using Windows.Graphics.Imaging;
using Windows.Media.Ocr;

namespace ocr_test
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

        }

        private async void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // 画像ファイルの読み込みと表示
            Stream input_stream = new FileStream("test.png", FileMode.Open, FileAccess.Read, FileShare.Read);
            var source = new WriteableBitmap(System.Windows.Media.Imaging.BitmapFrame.Create(input_stream));
            imgSrc.Source = source;
            input_stream.Close();

            // 画像データをメモリストリームへ書き出し
            PngBitmapEncoder encoder = new PngBitmapEncoder();
            encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(source));
            MemoryStream temp_stream = new MemoryStream();
            encoder.Save(temp_stream);

            // メモリストリームを変換
            var converted_stream = WindowsRuntimeStreamExtensions.AsRandomAccessStream(temp_stream);

            // メモリストリームからOCR用画像データの生成
            var decorder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(converted_stream);
            SoftwareBitmap bitmap = await decorder.GetSoftwareBitmapAsync();
            converted_stream.Dispose();
            temp_stream.Close();

            // OCRの実行
            OcrEngine engine = OcrEngine.TryCreateFromLanguage(new Windows.Globalization.Language("ja-JP"));
            var result = await engine.RecognizeAsync(bitmap);

            txtResult.Text = result.Text;
        }
    }
}

System.IO.MemoryStreamからWindows.Storage.Streams.IRandomAccessStreamへの変換に、WindowsRuntimeStreamExtensions.AsRandomAccessStreamというメソッドを使用しています。これを使うためには、System.Runtime.WindowsRuntimeを参照に追加する必要があります。NuGetでインストールし忘れていないか確認してください。

上記のコードでは、OCRエンジンに日本語を指定しています。英語にしたい場合などには、Windows10に言語パックのインストールが必要のようです。

文字認識の例

実際に実行すると、このような結果になります。

OCR結果

文章の順番のずれについてはプログラム側で工夫できると思います。

「ル」が「ノレ」になってしまっているのがちょっと残念ですね。

まあでも、こんなに簡単にOCRができてしまうのはありがたいことです。

主なメソッド

WindowsRuntimeStreamExtensions.AsRandomAccessStream

dst = WindowsRuntimeStreamExtensions.AsRandomAccessStream(src);

変数

内容

src

System.IO.Stream

変換元のストリーム

dst

IRandomAccessStream

変換後のストリーム

System.IO.Streamクラスのオブジェクトを、Windows.Storage.Streams.IRondomAccessStreamクラスのオブジェクトに変換します。

BitmapDecoder.CreateAsync

decoder = Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(stream);

変数

内容

stream

IRandomAccessStream

入力用のストリーム

decoder

BitampDecoder

デコーダーインスタンス

非同期のメソッドです。ストリームからBitmapDecoderインスタンスを生成します。

System.Windows.Media.ImagingにもBitmapDecoderがありますので、上記のように明示が必要になる場合があります。

BitmapDecoder.GetSoftwareBitmapAsync

bitmap = decoder.GetSoftwareBitmapAsync();

変数

内容

decoder

BitampDecoder

デコーダーインスタンス

bitmap

SoftwareBitmap

Bitmapオブジェクト

非同期のメソッドです。実行が終わると、BitmapDecoderインスタンスから生成したSoftwareBitmapオブジェクトを返します。

OcrEngine.TryCreateFromLanguage

engine = OcrEngine.TryCreateFromLanguage(language);

変数

内容

language

Language

OCR言語の指定

engine

OcrEngine

OCRエンジンのインスタンス

OcrEngineクラスのインスタンスを生成します。

language引数に言語を指定します。この引数には、Windows.Globalization.Languageクラスのインスタンスを指定します。Languageクラスのコンストラクタ引数にja-JPを指定すると日本語になります。

Windows10の規定の言語に設定したい場合は、TryCreateFromUserProfileLanguagesというメソッドもあります。

OcrEngine.RecognizeAsync

result = engine.RecognizeAsync(bitmap);

変数

内容

engine

OcrEngine

OCRエンジンのインスタンス

bitmap

SoftwareBitmap

入力画像

result

OcrResult

OCRの結果

非同期のメソッドです。実行が終わると、OcrResultクラスのオブジェクトを返します。

OcrResultクラスには、Lines、Text、TextAngleというプロパティがあります。Textプロパティを参照すると、OCRの結果の文字列が得られます。

公開日

広告