C#

【C#】文字認識をWindows10のOCRでやってみた!

C#で画像データの中にある文字を認識するにはどうしたらいいか調べた結果、Windows10にOCR(文字認識)機能が標準で備わっていることが分かりました。

本記事ではWindows10の文字認識機能を用いて、画像データの文字を認識してテキストデータとして出力するプログラミング方法をまとめてみました。

文字認識をやってみたいという方は是非参考にしてみてください。

環境

OSWindows10
IDEVisual Studio 2019
フレームワーク.NET Core3.1
UIフレームワークWPFアプリ

OCR(光学文字認識)とは…

OCR(Optical Character Recognition/Reader)とは印刷された文字や手書きの文字、画像の文字などをスキャナやデジタルカメラといった光学的な手段によって取り込みをし、コンピューターが利用できるデジタル文字コード(テキスト)に変換する技術のことをさします。 

文字認識機能を活用することにより、さまざまな帳票類や文書を効率的にデータ化することが可能になります。

データ入力作業の手間を大幅に削減し2重入力や人的ミスの削減などを行えるため、業務プロセスが効率化されることが期待されます。そのため現在では大手企業はじめ、中小企業でも文字認識機能の導入による業務プロセス効率化を進める企業が多く存在します。 

OCRの仕組み

文字認識の基本的な仕組みをフローチャートにした図が以下になります。

①紙をスキャンし、画像データにする
元になる紙をスキャナや複合機などでスキャンし、画像データに変換します。

②画像データをレイアウト解析する
画像の中から画像処理を駆使し文字の箇所を特定します。背景のイラストや罫線など、画像内には文字とは全く関係ない情報と文字を区別します。

③文字列を項目単位で切り出す
レイアウト解析したデータを元に文字列を項目単位で切り出します。文字列を1文字ずつ文字の種類を識別していきます。

④OCRを実行
識別した情報をテキスト・データとしてパソコンやタブレットなどのデバイスに表示します。

文字認識機能の活用例

文字認識機能をアプリケーションに組み込みすれば、「レシートや領収書などからデータを取り込む家計簿アプリ」や「印刷された書類などをテキストデータ化するアプリ」など様々なアプリを作成することができます。

  • レシートや領収書などからデータを取り込む家計簿アプリ
  • 印刷された書類などをテキストデータ化するアプリ
  • 名刺に印字されている情報を取り込む名刺管理アプリ

OCRエンジンの種類

C#で文字認識を扱う方法には、以下に記載している3つのエンジンを使用する方法があります。

  1. Windows10に標準搭載されているMicrosoft OCRのOCRエンジン
  2. Apache Licenseが提供するTeseractのOCRエンジン
  3. クラウドサービス系のOCRエンジン(Microsoft Azure Computer Vision APIGoogle Cloud Vision API

今回は①のWindows 10標準搭載のOCRエンジンを使いながら、C#で作成したアプリから画像ファイルの文字認識を試してみます。

Microsoft OCRについて

プロジェクトのUIフレームワークに応じて使い方が異なります。WPFの場合はNuGetから「Microsoft.Windows.SDK.Contracts」をインストールする必要があります。

WPFやFormの場合コードのヘッダ部分にusing Windows.Media.Ocr;を書くことで使うことができる。
UWPの場合NuGetから「Microsoft.Windows.SDK.Contracts」をインストールする。

Microsoft.Windows.SDK.Contractsの使い方

NuGetからパッケージをダウンロード

Microsoft Visual Studioから任意のプロジェクトを開きます。ソリューションエクスプローラーの中にあるプロジェクト名を選択して右クリックをすると、表示される項目の中にある「NuGetパッケージの管理(N)…」をクリックします。

NuGetパッケージマネージャーが開くので、検索欄に「microsoft windows sdk contracts」と入力して検索します。検索結果一覧の中にある「Microsoft.Windows.SDK.Contracts」を選択して、パッケージをインストールします。

名前空間の参照先追加

続いて異なる名前空間に定義されているクラスを使用できるように、ファイルの先頭でusingディレクティブを記述します。この記述を行うことで、コードの入力手間を省くことができます。
using System.Windows.Media.Imaging;
using Windows.Graphics.Imaging;
using Windows.Media.Ocr;

OCRを実行する関数の作成

WPFで文字認識を実行する際の手順は以下になります。

Windows.Media.Ocr.OcrEngineで文字認識できる画像形式は、SoftwareBitmap形式です。この形式へ画像データを変換することでOCRによる文字認識が実行されます。

WPFのイメージコントロールから画像データを取得し、文字認識を実行する関数は以下になります。
private async Task<SoftwareBitmap> ConvertSoftwareBitmap(Image image)
{
    SoftwareBitmap sbitmap = null;

    using (MemoryStream stream = new MemoryStream())
    {
        //BmpBitmapEncoderに画像を書きこむ
        var encoder = new BmpBitmapEncoder();
        encoder.Frames.Add((System.Windows.Media.Imaging.BitmapFrame)image.Source);
        encoder.Save(stream);

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

        //画像データをSoftwareBitmapに変換
        var decorder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(irstream);
        sbitmap = await decorder.GetSoftwareBitmapAsync();
    }

    return sbitmap;
}

private async Task<OcrResult> RunOcr(SoftwareBitmap sbitmap)
{
    //OCRを実行する
    OcrEngine engine = OcrEngine.TryCreateFromLanguage(new Windows.Globalization.Language("ja-JP"));
    var result = await engine.RecognizeAsync(sbitmap);
    return result;
}

RecognizeAsyncの結果であるOcrResultをTextプロパティで出力することで認識結果を取得することができます。

サンプル使用例

上記で説明したサンプルコードを使用して、WPFで文字認識するアプリケーションを作成してみます。

文字認識する画像データのファイルパスを入力欄に入力し、OCR実行ボタンをクリックすれば、文字認識した結果がテキストボックスに出力されます。画面はマテリアルデザインを適用させてオシャレな画面に仕上げました。


マテリアルデザインの適用方法については、以下の記事で詳しく記載しています。

https://marunaka-blog.com/material-design-xaml-toolkit_wpf_01/367/

XAMLのソースは以下の記述になります。
<Window
    x:Class="OCRsample.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:local="clr-namespace:OCRsample"
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="600"
    Height="450"
    WindowStyle="None"
    mc:Ignorable="d">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="55" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <!--  ヘッダー  -->
        <materialDesign:ColorZone
            Grid.Row="0"
            Height="50"
            Padding="12"
            Mode="PrimaryMid">
            <DockPanel>
                <materialDesign:PopupBox DockPanel.Dock="Right" PlacementMode="BottomAndAlignRightEdges">
                    <ListBox>
                        <ListBoxItem Content="Close" />
                    </ListBox>
                </materialDesign:PopupBox>
                <StackPanel Orientation="Horizontal">
                    <materialDesign:PackIcon
                        Width="26"
                        Height="26"
                        Kind="Ocr" />
                    <TextBlock
                        Margin="16,0,0,0"
                        VerticalAlignment="Center"
                        Text="OCR SAMPLE" />
                </StackPanel>
            </DockPanel>
        </materialDesign:ColorZone>
        <Label
            x:Name="lblPath"
            Grid.Row="1"
            Width="92"
            Margin="10,18,0,0"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            HorizontalContentAlignment="Right"
            Content="ファイルパス:" />
        <TextBox
            x:Name="txtPath"
            Grid.Row="1"
            Margin="110,5,175,0"
            VerticalAlignment="Top"
            materialDesign:HintAssist.Hint="イメージファイルのパスを入力してください。"
            Style="{StaticResource MaterialDesignFloatingHintTextBox}" />
        <Button
            Name="btnPath"
            Grid.Row="1"
            Width="70"
            Margin="0,10,100,0"
            HorizontalAlignment="Right"
            VerticalAlignment="Top"
            Click="btnPath_Click"
            Content="参照..."
            FontSize="12"
            Style="{StaticResource MaterialDesignPaperDarkButton}" />
        <Button
            Name="btnOcr"
            Grid.Row="1"
            Width="85"
            Margin="0,10,10,0"
            HorizontalAlignment="Right"
            VerticalAlignment="Top"
            Click="btnOcr_Click"
            Content="OCR実行"
            FontSize="12" />
        <Image
            x:Name="ImgTarget"
            Grid.Row="2"
            Margin="10,10,10,100" />
        <TextBox
            Name="txtOcrResult"
            Grid.Row="2"
            Margin="10,255,10,10"
            VerticalAlignment="Bottom"
            materialDesign:HintAssist.Hint="OCRの実行結果"
            AcceptsReturn="True"
            IsEnabled="{Binding Path=IsChecked, ElementName=MaterialDesignOutlinedTextBoxEnabledComboBox}"
            Style="{StaticResource MaterialDesignOutlinedTextBox}"
            TextWrapping="Wrap"
            VerticalScrollBarVisibility="Auto" />
    </Grid>
</Window>
コードは以下の記述になります。
namespace OCRsample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void btnPath_Click(object sender, RoutedEventArgs e)
        {
            ImgTarget.Source = null;
            txtPath.Text = "";

            await Task.Delay(10);

            //画像ファイルのパスを取得
            txtPath.Text = SelectPath();

            if (txtPath.Text != "")
            {
                //画像ファイルの読み込み
                ImgTarget.Source = System.Windows.Media.Imaging.BitmapFrame.Create(new Uri(txtPath.Text, UriKind.Absolute), BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
            }
        }

        private string SelectPath()
        {
            var path = "";

            // ダイアログのインスタンスを生成
            var dialog = new OpenFileDialog();

            // ファイルの種類を設定
            dialog.Filter = "Image File(*.bmp, *.jpg, *.png, *.tif) | *.bmp; *.jpg; *.png; *.tif | Bitmap(*.bmp) | *.bmp | Jpeg(*.jpg) | *.jpg | PNG(*.png) | *.png";

            // ダイアログを表示する
            if (dialog.ShowDialog() == true)
            {
                // 選択されたファイル名を取得
                path = dialog.FileName;
            }

            return path;
        }

        private async void btnOcr_Click(object sender, RoutedEventArgs e)
        {
            //OCRの実行処理
            var sbitmap = await ConvertSoftwareBitmap(ImgTarget);
            txtOcrResult.Text = (await RunOcr(sbitmap)).Text;
        }
    }
}

さっそくアプリケーションを動かしてみましょう。
参照ボタンから画像ファイルを選択し、OCR実行ボタンをクリックします。下図のように画像データから認識した文字情報が表示されました。

まとめ

この記事ではWindows10標準搭載の文字認識機能をC#(WPF)で使う方法についてまとめました。

動くことまで確認できたのでフォントを変えたり文字サイズを変えたりしたら、どうなるのか確認もしてみたいですね。

またC#で文字認識を扱う方法は他にもあるので、時間をとって調べてみたいと思います。

以上、最後まで読んでいただきありがとうございました。

プログラミングを学習したいなら…

プログラミングスキルを身に付けるなら、プログラミングを効率良く学べる
プログラミングスクール」がオススメです。

特にこんな方にオススメ!!
これからエンジニアを目指したい
プログラミングの専門性を高めたい
プログラミングを学んで副業をしたい
エンジニアに転職して年収をアップさせたい

プログラミングを触ったことがない未経験からでも、プログラミングスクールで学習すれば、エンジニアへ就職・転職することも可能です。

あなたの「行動力」と「やる気」で、あなたの人生を大きく変えるチャンスになることでしょう。

プログラミングスクールに興味がある方は是非チェックしてみてください。

> プログラミングを学ぶ <

COMMENT

メールアドレスが公開されることはありません。

CAPTCHA