Tesseractのtraineddataを作る(解析結果がいまいち)

とりあえず、こちらでMNISTの画像を学習させた辞書をつくりました。
eng_best辞書にMNISTを再学習させてもみたけど、今回はひとまずMNISTだけの話。


解析させて思ったこと

  • 1~2文字だとEmptyとみなしてくる
    画像が小さいことが原因ではない(拡大しても同じ)
    eng辞書でも同じ。
    『1   23  』ならかろうじて『23』部分だけ拾う
  • 3文字以上なら認識出来ている(画像を拡大しても認識する)
  • 縦に空白が多いと、認識しないか『8』とみなしがち

はい、というわけで、解析前に余白をなるべくカットすることは必要そう。

あと、単一文字だと認識しないのは、PSM値が関係ある?
こちらによると初期値は13って書いてあるのに、詳細が書いてない。なんてこった。

こちらこちらを信じれば、8(single word)よりは10(single character)でしょうかね。
ただ、こちらは学習時ではなく使うときに指定する値だね?
学習時に指定することと、使うときに指定することの関係がよくわからん。

PSMを指定

使う側から指定

Ubuntu上のtesseractコマンドには、PSMを指定するオプションがありませんでした。
C#製ライブラリから使いたくて辞書を作ったので、Tesseract.TesseractEngineクラスを確認。
ありました! DefaultPageSegMode!

簡単なツールを作って実験してみる。

using System;
using System.Windows.Forms;
using System.IO;
using Tesseract;

namespace TestTesseractTraineddata
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void bunRun_Click(object sender, EventArgs e)
        {
            ResultBox.ResetText();
            try
            {
                // 言語をリストアップ
                string traineddataDir = TraineddataBox.Text;
                string[] traineddataLangName = Directory.GetFiles(TraineddataBox.Text);
                for (int i = 0; i < traineddataLangName.Length; i++)
                {
                    traineddataLangName[i] = Path.GetFileNameWithoutExtension(traineddataLangName[i]);
                }

                // ファイルごとに解析開始
                string[] Imagefiles = Directory.GetFiles(ImageBox.Text);
                for (int imgIdx = 0; imgIdx < Imagefiles.Length; imgIdx++)
                {
                    ResultBox.Text += "===========" + Imagefiles[imgIdx] + "解析結果===========\r\n";
                    for (int lngIdx = 0; lngIdx < traineddataLangName.Length; lngIdx++)
                    {
                        using (var tesseract = new TesseractEngine(traineddataDir, traineddataLangName[lngIdx]))
                        {
                            tesseract.DefaultPageSegMode = (PageSegMode)(PSMBox.Value);
                            using (var img = Pix.LoadFromFile(Imagefiles[imgIdx]))
                            {
                                // OCRの実行
                                using (Page page = tesseract.Process(img))
                                {
                                    ResultBox.Text += (lngIdx + 1) + " : " + traineddataLangName[lngIdx] + "\r\n" + page.GetText() + "\r\n";
                                    ResultBox.Refresh();
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ResultBox.Text = ex.Message;
            }
        }

        /// <summary>
        /// Form自体のりサイズ
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Resize(object sender, EventArgs e)
        {
            // 結果表示エリアを追随させる
            ResultBox.Width = this.Width - (ResultBox.Left * 2);
            ResultBox.Height = this.Height - ResultBox.Top - 50;
        }

        private void PSMHelpBtn_Click(object sender, EventArgs e)
        {
            MessageBox.Show("OsdOnly = 0\r\nAutoOsd = 1\r\nAutoOnly = 2\r\nAuto = 3\r\nSingleColumn = 4\r\nSingleBlockVertText = 5\r\nSingleBlock = 6\r\nSingleLine = 7\r\nSingleWord = 8\r\nCircleWord = 9\r\nSingleChar = 10\r\nSparseText = 11\r\nSparseTextOsd = 12\r\nRawLine = 13\r\n");
        }
    }
}

DefaultPageSegModeをコロコロ変えてみると、解析結果がずいぶん変わりました!
やっぱり10を指定すると、Emptyになることはなく、解析してくれます。いいね。

学習時の指定

上で実験したときは、なにも考えずに学習させた辞書を使っていました。
つまり、13(1行の文章)かな?

そして、1文字ずつ切り取って学習させた辞書と、40文字ずつ切り取って学習させた辞書でも微妙に結果が違う。
気持ち、40文字辞書の方が良い結果を返してくれてる、気がしなくもない。
PSM=13がいい感じに効いているのでしょうか?
40文字ずつでeng_bestに再学習させた辞書の方がさらに精度は高そう。
1文字ずつ切り取ったデータで、PSMに10を指定して、辞書を再作成してみましょう。

nohup time -f "Run time = %E\n" make training MODEL_NAME=mnist PSM=10 >> train.log 2>&1 &

ちょっと認識率良くなりました。
でも体感として、1文字 < 1文字PSM=10 < 40文字辞書 < eng_bestに40文字で再学習って感じ。

MNISTの学習画像を解析してみた

いろんな辞書を作ったので、PSM=10を指定してMNISTの画像(1画像につき1文字)を解析してみました。
「補正あり」は、ゼロの画像にアルファベットのオー返しても正解、みたいな感じで補正して計測。

辞書正解率補正あり
eng51%63%
eng_best38%52%
eng_bestにMNISTを再学習95%95%
eng_bestにMNISTを再学習して警告対策95%96%
MNISTを1文字ずつPSM=10で学習8%
MNISTを1文字ずつPSM=13で学習8%
MNISTを40文字ずつ学習76%
EMNISTを40文字ずつ学習40%53%
eng_bestにEMNISTを再学習71%86%

少なくとも、1文字ずつより、ある程度の塊で学習させる方が良さそう。
数字や限られた記号だけを認識するためなら、下手に他の文字を学習させすぎるのも考えもの、って印象。

てか、そもそも人間の目から見ても「それ、どっちなん??」って文字、結構あるな???


他にもニッチなIT関連要素をまとめていますので、よければ一覧記事もご覧ください。

返信を残す

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

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)