C# で画像データの中にある文字を認識するにはどうしたらいいか調べた結果、Windows10 に OCR(文字認識)機能が標準で備わっていることが分かりました。
本記事では Windows10 の文字認識機能を用いて、画像データの文字を認識してテキストデータとして出力するプログラミング方法をまとめてみました。
文字認識をやってみたいという方は是非参考にしてみてください。
環境
項目 | 内容 |
---|---|
OS | Windows10 |
IDE | Visual Studio 2019 |
フレームワーク | .NET Core3.1 |
UIフレームワーク | WPFアプリ |
オススメの参考書
C#の使い方が丁寧に解説しており、「基礎からしっかりと学びたい」という初心者の方にオススメの一冊です。サンプルコードも記載してあり、各章の最後に復習問題があるので理解度を確認しながら読み進めることができます。新しい C# のバージョンにも対応している書籍です。
OCR(光学文字認識)とは…
OCR(Optical Character Recognition/Reader)とは印刷された文字や手書きの文字、画像の文字などをスキャナやデジタルカメラといった光学的な手段によって取り込みをし、コンピューターが利用できるデジタル文字コード(テキスト)に変換する技術のことをさします。
文字認識機能を活用することにより、さまざまな帳票類や文書を効率的にデータ化することが可能になります。
データ入力作業の手間を大幅に削減し2重入力や人的ミスの削減などを行えるため、業務プロセスが効率化されることが期待されます。そのため現在では大手企業はじめ、中小企業でも文字認識機能の導入による業務プロセス効率化を進める企業が多く存在します。
OCRの仕組み
文字認識の基本的な仕組みをフローチャートにした図が以下になります。
①紙をスキャンし、画像データにする
元になる紙をスキャナや複合機などでスキャンし、画像データに変換します。
②画像データをレイアウト解析する
画像の中から画像処理を駆使し文字の箇所を特定します。背景のイラストや罫線など、画像内には文字とは全く関係ない情報と文字を区別します。
③文字列を項目単位で切り出す
レイアウト解析したデータを元に文字列を項目単位で切り出します。文字列を1文字ずつ文字の種類を識別していきます。
④OCRを実行
識別した情報をテキスト・データとしてパソコンやタブレットなどのデバイスに表示します。
文字認識機能の活用例
文字認識機能をアプリケーションに組み込みすれば、「レシートや領収書などからデータを取り込む家計簿アプリ」や「印刷された書類などをテキストデータ化するアプリ」など様々なアプリを作成することができます。
- レシートや領収書などからデータを取り込む家計簿アプリ
- 印刷された書類などをテキストデータ化するアプリ
- 名刺に印字されている情報を取り込む名刺管理アプリ
OCRエンジンの種類
C#で文字認識を扱う方法には、以下に記載している3つのエンジンを使用する方法があります。
- Windows10に標準搭載されているMicrosoft OCRのOCRエンジン
- Apache Licenseが提供するTeseractのOCRエンジン
- クラウドサービス系のOCRエンジン(Microsoft Azure Computer Vision API、Google 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 実行ボタンをクリックすれば、文字認識した結果がテキストボックスに出力されます。画面はマテリアルデザインを適用させてオシャレな画面に仕上げました。
マテリアルデザインの適用方法については、以下の記事で詳しく記載しています。
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#で文字認識を扱う方法は他にもあるので、時間をとって調べてみたいと思います。
以上、最後まで読んでいただきありがとうございました。