画像をモノクロ化することでTesseract OCRの精度は上がることがわかりました。
では以下のような画像の場合、正しく文字を認識することができるでしょうか?
モノクロ化してもしなくても正しく文字を認識することはできません。文字が斜めになっている場合はうまくいかないようです。そこで画像を回転させることを考えます。
90度、180度、270度であれば以下の方法で簡単に回転処理をすることができます。
しかし10度だけ回転させる場合はこの方法は使えません。
ではどうすればいいのでしょうか? アフィン変換をするとうまくいきそうです。
このサイトを参考にしました。
【C#】アフィン変換の相互座標変換 | イメージングソリューション
アフィン変換を使ってできることは回転処理だけではありません。もっと広い処理ができます。ただここは回転処理に限定してやってみます。
まずアフィン変換行列を作ります。
1 |
System.Drawing.Drawing2D.Matrix matAffine = new System.Drawing.Drawing2D.Matrix(); |
これでアフィン変換行列は完成です。そしてこれに回転処理を加えます。
1 |
matAffine.Rotate(30, System.Drawing.Drawing2D.MatrixOrder.Append); |
第一引数で30を指定しているのは30度回転させるという意味です。弧度法ではなく度数法で指定します。
そのあと・・・・
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// Bitmap srcBitmapはすでに与えられている Bitmap newBitmap = new Bitmap(Width, Height); using (var g = Graphics.FromImage(newBitmap)) { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; var srcRect = new RectangleF(-0.5f, -0.5f, srcBitmap.Width, srcBitmap.Height); // 描画先の座標(描画元に合わせる、左上、右上、左下の順) var points = new PointF[] { new PointF(srcRect.Left, srcRect.Top), new PointF(srcRect.Right, srcRect.Top), new PointF(srcRect.Left, srcRect.Bottom), }; // 描画先の座標をアフィン変換で求める(変換後の座標は上書きされる) matAffine.TransformPoints(points); // 描画 g.DrawImage(srcBitmap, points, srcRect, GraphicsUnit.Pixel); } |
これで得られたnewBitmapをファイルとして保存すれば回転させることはできます。
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 |
public partial class Form1 : Form { void RotateImage(string inputFilePath, string newFilePath, int Rotate) { System.Drawing.Drawing2D.Matrix matAffine = new System.Drawing.Drawing2D.Matrix(); matAffine.Rotate(Rotate, System.Drawing.Drawing2D.MatrixOrder.Append);//回転 using(Bitmap srcBitmap = new Bitmap(inputFilePath)) using(Bitmap newBitmap = new Bitmap(srcBitmap.Width, srcBitmap.Height)) using(var g = Graphics.FromImage(newBitmap)) { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; var srcRect = new RectangleF(-0.5f, -0.5f, srcBitmap.Width, srcBitmap.Height); // 描画先の座標(描画元に合わせる、左上、右上、左下の順) var points = new PointF[] { new PointF(srcRect.Left, srcRect.Top), new PointF(srcRect.Right, srcRect.Top), new PointF(srcRect.Left, srcRect.Bottom), }; // 描画先の座標をアフィン変換で求める(変換後の座標は上書きされる) matAffine.TransformPoints(points); // 描画 g.DrawImage(srcBitmap, points, srcRect, GraphicsUnit.Pixel); //newBitmapを保存する newBitmap.Save(newFilePath); } return; } private void button1_Click(object sender, EventArgs e) { string filePath = textBox1.Text; // このファイルが本当に存在するか確認する if(!File.Exists(filePath)) { MessageBox.Show("ファイルが存在しない"); return; } // 保存場所は元のファイルがあったフォルダ内に // outputというフォルダを作成してそこに保存する FileInfo info = new FileInfo(filePath); string outputFolderPath = info.DirectoryName + "\\output"; // フォルダがなければ作る if(!Directory.Exists(outputFolderPath)) Directory.CreateDirectory(outputFolderPath); // 処理後の画像ファイルは newFilePathに保存する string newFilePath = outputFolderPath + "\\" + info.Name; RotateImage(filePath, newFilePath, -10); } } |
回転角は-10度を指定するとほぼ水平になりました。
この方法で文字認識できるかどうかやってみると
毎日がんばる私の
がんばらない
できた!