Windows10のOCR利用 画像より文字抽出 VB.NET
開発メモ その266 Windows 10 の OCR を試してみる (.NET Framework) を参照して OCR機能に読み取り結果をテキストファイルとして出力することを追加。(開発言語は、c#)
OCR機能は、画像全体と選択範囲を指定してテキストを出力
OCR読み取りは、C#で開発したOcrR.exeを使用。OCR読み取りの結果は、ファイル出力する。出力ファイルより読み取り結果をテキストBOXへ読み込みます。表示された画像から読み取り範囲を指定してOCR読み取りが可能。
画面設計
Form1.vb
Imports System.Security.Cryptography
Public Class Form1
'画像用の座標
Private pos As Point
'Form1オブジェクトを保持するためのフィールド
Public Shared Form1Instance As Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Form1.Form1Instance = Me
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
open()
End Sub
Private Sub open()
'OpenFileDialogクラスのインスタンスを作成
Dim ofd As New OpenFileDialog()
'はじめのファイル名を指定する
'はじめに「ファイル名」で表示される文字列を指定する
ofd.FileName = "default.jpg"
'はじめに表示されるフォルダを指定する
'指定しない(空の文字列)の時は、現在のディレクトリが表示される
ofd.InitialDirectory = System.Environment.CurrentDirectory
'[ファイルの種類]に表示される選択肢を指定する
'指定しないとすべてのファイルが表示される
ofd.Filter = "jpeg-pngファイル(*.jpg;*.png)|*.jpgl;*.png|すべてのファイル(*.*)|*.*"
'[ファイルの種類]ではじめに選択されるものを指定する
'2番目の「すべてのファイル」が選択されているようにする
ofd.FilterIndex = 2
'タイトルを設定する
ofd.Title = "開くファイルを選択してください"
'ダイアログボックスを閉じる前に現在のディレクトリを復元するようにする
ofd.RestoreDirectory = True
'存在しないファイルの名前が指定されたとき警告を表示する
'デフォルトでTrueなので指定する必要はない
ofd.CheckFileExists = True
'存在しないパスが指定されたとき警告を表示する
'デフォルトでTrueなので指定する必要はない
ofd.CheckPathExists = True
'ダイアログを表示する
If ofd.ShowDialog() = DialogResult.OK Then
'OKボタンがクリックされたとき、選択されたファイル名を表示する
Console.WriteLine(ofd.FileName)
TextBox1.Text = ofd.FileName
'画像ファイルを読み込んで、Imageオブジェクトを作成する
Dim img As System.Drawing.Image = System.Drawing.Image.FromFile(TextBox1.Text)
'画像を表示する
PictureBox1.Image = img
End If
End Sub
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
End
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
ocr()
End Sub
Private Sub ocr()
Label3.Text = System.Environment.CurrentDirectory
Dim Ret As Long
Dim MyFile As String
MyFile = Label3.Text & "\OcrR.exe" & " " & TextBox3.Text & " " & TextBox1.Text
Ret = Shell(MyFile, vbNormalFocus, True, 60000)
'Shift-JISコードとして開く
Dim sr As New System.IO.StreamReader(Label3.Text & "\test.txt",
System.Text.Encoding.GetEncoding("UTF-8"))
'内容をすべて読み込む
Dim s As String = sr.ReadToEnd()
'閉じる
sr.Close()
TextBox2.Text = TextBox2.Text + vbCrLf + Replace(s, " ", "")
End Sub
Private Sub PictureBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseUp
Dim img As Image = PictureBox1.Image
pos.X = e.X * img.Width / PictureBox1.Width
pos.Y = e.Y * img.Height / PictureBox1.Height
TextBox4.Text = TextBox4.Text + Str(pos.X) + "," + Str(pos.Y) + ","
Dim xy() = Split(TextBox4.Text, ",")
If xy.Length > 4 Then
TextBox5.Text = xy(xy.Length - 5)
TextBox6.Text = xy(xy.Length - 4)
TextBox7.Text = xy(xy.Length - 3)
TextBox8.Text = xy(xy.Length - 2)
TextBox4.Text = xy(xy.Length - 5) + ","
TextBox4.Text += xy(xy.Length - 4) + ","
TextBox4.Text += xy(xy.Length - 3) + ","
TextBox4.Text += xy(xy.Length - 2) + ","
End If
End Sub
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
ocr_part()
End Sub
Private Sub ocr_part()
'元画像
Dim source As Bitmap
source = New Bitmap(TextBox1.Text)
'切り取るサイズ
Dim x1 = Int(TextBox5.Text)
Dim y1 = Int(TextBox6.Text)
Dim x2 = Int(TextBox7.Text)
Dim y2 = Int(TextBox8.Text)
Dim rect As Rectangle
rect = New Rectangle(x1, y1, x2 - x1, y2 - y1)
'切り取り後の画像
Dim trimed As Bitmap
trimed = source.Clone(rect, source.PixelFormat)
'保存
trimed.Save("trimed.jpg")
source.Dispose()
trimed.Dispose()
Label3.Text = System.Environment.CurrentDirectory
Dim Ret As Long
Dim MyFile As String
MyFile = Label3.Text & "\OcrR.exe" & " " & TextBox3.Text & " " & Label3.Text & "\trimed.jpg"
Ret = Shell(MyFile, vbNormalFocus, True, 60000)
'Shift-JISコードとして開く
Dim sr As New System.IO.StreamReader(Label3.Text & "\test.txt",
System.Text.Encoding.GetEncoding("UTF-8"))
'内容をすべて読み込む
Dim s As String = sr.ReadToEnd()
'閉じる
sr.Close()
TextBox2.Text = TextBox2.Text + vbCrLf + Replace(s, " ", "")
End Sub
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
TextBox2.Text = ""
End Sub
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
hozon()
End Sub
Private Sub hozon()
'SaveFileDialogクラスのインスタンスを作成
Dim sfd As New SaveFileDialog()
'はじめのファイル名を指定する
'はじめに「ファイル名」で表示される文字列を指定する
sfd.FileName = "新しいファイル.txt"
'はじめに表示されるフォルダを指定する
'指定しない(空の文字列)の時は、現在のディレクトリが表示される
sfd.InitialDirectory = System.Environment.CurrentDirectory
'[ファイルの種類]に表示される選択肢を指定する
sfd.Filter = "TEXTファイル(*.txt)|*.txt|すべてのファイル(*.*)|*.*"
'[ファイルの種類]ではじめに選択されるものを指定する
'2番目の「すべてのファイル」が選択されているようにする
sfd.FilterIndex = 1
'タイトルを設定する
sfd.Title = "保存先のファイルを選択してください"
'ダイアログボックスを閉じる前に現在のディレクトリを復元するようにする
sfd.RestoreDirectory = True
'既に存在するファイル名を指定したとき警告する
'デフォルトでTrueなので指定する必要はない
sfd.OverwritePrompt = True
'存在しないパスが指定されたとき警告を表示する
'デフォルトでTrueなので指定する必要はない
sfd.CheckPathExists = True
'ダイアログを表示する
If sfd.ShowDialog() = DialogResult.OK Then
'OKボタンがクリックされたとき、選択されたファイル名を表示する
'Console.WriteLine(sfd.FileName)
'Shift JISで書き込む
'書き込むファイルが既に存在している場合は、上書きする
Dim sw As New System.IO.StreamWriter(sfd.FileName,
False,
System.Text.Encoding.GetEncoding("UTF-8"))
'TextBox1.Textの内容を書き込む
sw.Write(TextBox2.Text)
'閉じる
sw.Close()
End If
End Sub
Private Sub 選択ToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles 選択ToolStripMenuItem.Click
open()
End Sub
Private Sub OCR全体処理ToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OCR全体処理ToolStripMenuItem.Click
ocr()
End Sub
Private Sub OCR選択処理ToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OCR選択処理ToolStripMenuItem.Click
ocr_part()
End Sub
Private Sub 消去ToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles 消去ToolStripMenuItem.Click
TextBox2.Text = ""
End Sub
Private Sub 保存ToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles 保存ToolStripMenuItem.Click
hozon()
End Sub
Private Sub 終了ToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles 終了ToolStripMenuItem.Click
End
End Sub
Private Sub Label4_Click(sender As Object, e As EventArgs) Handles Label4.Click
Form2.ShowDialog()
End Sub
実行画面
画面選択ボタンを押下し。画像を選択します。マウスで読み取りする場所を始点(左上)と終点(右下)のBOXで指定します。OCR選択処理ボタンを押下。読み取り結果が、表示されます。保存ボタンでテキストファィルとして保存されます。読み取り結果は、テキストBOXへ追加されます。初期化する場合は、消去ボタンで初期化されます。OCR全体処理ボタンは、選択に関係なく全体をOCR読み取りします。言語は、既定 ja です。読み取り言語の言語環境を設定することで精度は向上します。
OcrR.Program
using NLog;
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Media.Ocr;
namespace OcrR
{
internal sealed class Program
{
private static void Main(string[] args)
{
if (args.Length != 2)
{
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);
}
private static async Task<SoftwareBitmap> ConvertToSoftwareBitmap(byte[] image)
{
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)
{
Console.WriteLine("Failed to convert to SoftwareBitmap");
return null;
}
finally
{
}
}
private static byte[] GetImageBinary(string path)
{
try
{
return File.ReadAllBytes(path);
}
catch (Exception e)
{
Console.WriteLine("Failed to get image file binary");
return null;
}
finally
{
}
}
private static void RunOcr(OcrEngine ocrEngine, SoftwareBitmap bitmap)
{
try
{
var task = ocrEngine.RecognizeAsync(bitmap).AsTask();
task.Wait();
var text = task.Result.Text;
File.WriteAllText(System.IO.Directory.GetCurrentDirectory() + @"\test.txt", text);
Console.WriteLine(text);
}
catch (Exception e)
{
Console.WriteLine("Failed to run ocr");
}
finally
{
}
}
private static bool TrySetupOcrEngine(string languageTag, out OcrEngine engine)
{
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)
{
Console.WriteLine("Failed to create ocr engine because it could be lack of language pack.");
return false;
}
return true;
}
catch (Exception e)
{
Console.WriteLine("Failed to create ocr engine");
return false;
}
finally
{
}
}
}
}