リード開発メモ

大阪のソフトウェア会社です。 技術的な事柄についてのメモとしてブログを始めます。

tesseract-ocr

文字認識(その3)

前回 tesseracrt-ocr のトレーニングをやってみたが、認識率はあまりよくならなかった。もうすこしデータを増やさないといけないのかもしれない。

前回作ったトレーニング用の画像は、Wordを使って等幅の明朝フォント作った文書をキャプチャしたものだったので、同じ文書を等幅ゴシックに変えるだけの画像を追加してみる。 これだとBoxファイルは共通で使えるため、一番手間のかかるBoxファイルの修正が不要となる。ただトレーニングの効果はあまりないかもしれないが。。。

まず、jpn.gothic.exp0.jpg という名前で等幅ゴシックの画像を用意する。Boxファイルの名前は前回明朝フォントで使ったものをコピーして、名前をjpn.gothic.exp0.boxとしておく。

以下、手順3から。説明は省く。

3.トレーニングの実行
>tesseract jpn.mincho.exp0.jpg jpn.gothic.exp0 nobatch box.train.stderr


4.キャラクターセットの計算
>unicharset_extractor jpn.mincho.exp0.box jpn.gothic.exp0.box


5. font_propertiesファイル作成
>del font_properties
>echo mincho 0 0 0 0 0 >>font_properties
>echo gothic 0 0 0 0 0 >>font_properties


6. クラスタリング
>mftraining -F font_properties -U unicharset -O jpn.unicharset jpn.mincho.exp0.tr jpn.gothic.exp0.tr


続けて
>cntraining jpn.mincho.exp0.tr jpn.gothic.exp0.tr


7. 生成されたファイルのリネーム
>del jpn.inttemp
>ren inttemp jpn.inttemp
>del jpn.shapetable
>ren shapetable jpn.shapetable
>del jpn.pffmtable
>ren pffmtable jpn.pffmtable
>del jpn.normproto
>ren normproto jpn.normproto


8. 1ファイルにまとめる
>combine_tessdata jpn.



そして認識結果。。。良くなってないような気がする。
ocr14

以上です。

文字認識(その2)

今回はtesseracrt-ocr の認識率をあげるやめ、トレーニングを行ってみる。

前回はC++での開発に必要となるライブラリのみをダウンロードしたのだが、トレーニングを行うためにはツール類が必要となるため、セットアップからインストールし直すことにする。セットアップ tesseract-ocr-setup-3.02.02.exe が、前回と同じく以下のページからダウンロードできる。
https://code.google.com/p/tesseract-ocr/downloads/list

セットアップを実行すると、デフォルトでは「C:\Program Files (x86)\Tesseract-OCR」にインストールされる。インストール先は環境変数にも TESSDATA_PREFIX として登録される模様。このフォルダの中に tessdata フォルダも作られており、以後このフォルダのトレーニングデータが参照される。

また、トレーニングを行うとき、Boxファイルを修正する段階で使うツールをダウンロードしておく。同様のツールはいくつかあるようだが、今回は QT Box Editor を使う。以下からバイナリ版がダウンロードでき、ここでは 「qt-box-editor-1.08win32.zip — Win32 static build of QT Box Editor 1.08」 をダウンロードした。
https://github.com/zdenop/qt-box-editor/downloads

QT Box Editor は起動して、Editor > Settings から設定を行っておく。環境変数 TESSDATA_PREFIX の値と言語を設定する。
ocr7
および、Font & Colors から以下も設定しておく。
ocr8

トレーニングの手順としてはざっと以下のような感じかと思う。
1. 画像の作成
2. Boxファイル作成
3.トレーニングの実行 4.キャラクターセットの計算
5. font_propertiesファイル作成
6. クラスタリング
7. 生成されたファイルのリネーム
8.1ファイルにまとめる


1. 画像の作成
特定のフォントのテキストが含まれる画像を用意する。形式は何でもいいと思うが、QT Box Editor が読み込める形式として jpeg にしておく。また、後々のためにファイル名を [言語コード].[フォント名].exp[連番] のとしておく。例えば「jpn.mincho.exp0.jpg」など。

2. Boxファイル作成
以下のコマンドで画像ファイルからBoxファイルを作成する。
>tesseract jpn.mincho.exp0.jpg jpn.mincho.exp0 -l jpn batch.nochop makebox

また、QT Box Editorに画像をドロップすると、まだBoxファイルが作られていなければ、以下のダイアログが表示されるので、Yes で Boxファイルを作ってくれる。
ocr9

Boxファイルは、画像と同じフォルダに jpn.mincho.exp0.box という名前で作成される。単なるテキストファイルで、画像ファイルから読み取った文字と座標が列挙されている。以下はQT Box EditorでBoxファイルを開いたところだが、左側にそれらの情報が表示されている。QT Box Editorはこの文字と座標の修正を行うために使う。
ocr10

左側で文字を選択すると、右側の画像の対応する位置に赤い枠が表示される。ここでは「は」の左側だけが「乙」として認識されているので修正する必要がありそうだ。赤い文字は前後数文字分の読み取り結果で、画像の対応する位置の少し上に表示される。 ocr11

おかしいところを修正した。これでBoxファイルを上書き保存する。
ocr12

3.トレーニングの実行
以下のコマンドを実行し、ファイル jpn.mincho.exp0.tr を生成される。
>tesseract jpn.mincho.exp0.jpg jpn.mincho.exp0 nobatch box.train.stderr


4.キャラクターセットの計算
以下のコマンドを実行し、ファイル unicharset を生成される。
>unicharset_extractor jpn.mincho.exp0.box


5. font_propertiesファイル作成
ファイル名 font_properties でファイルを作成する。内容は以下。
mincho 0 0 0 0 0


6. クラスタリング
次のコマンドを実行し、以下の4ファイルを作成する。
・shapetable
・inttemp
・pffmtable
・jpn.unicharset
>mftraining -F font_properties -U unicharset -O jpn.unicharset jpn.mincho.exp0.tr


続けて、次のコマンドを実行し、以下のファイルを作成する。
・normproto
>cntraining jpn.mincho.exp0.tr


7. 生成されたファイルのリネーム
>ren inttemp     jpn.inttemp
>ren shapetable  jpn.shapetable
>ren pffmtable   jpn.pffmtable
>ren normproto   jpn.normproto


8.1ファイルにまとめる
次のコマンドを実行し、jpn.traineddata を生成する。
>combine_tessdata jpn.


生成されたファイルがトレーニングデータとなる。jpn.traineddata は元々存在した jpn.traineddata を上書きしないよう jpn1.traineddata という名前に変更して、tessdata フォルダに置く。

プログラムから使う場合、以下のようにする。ちなみに Init メソッドの最初の引数は tessdata フォルダを指すが、tesseract-ocr をインストールしたことによりわざわざ指定する必要がなくなったため、NULLにしてある。
	tesseract::TessBaseAPI tess;
	tess.Init(NULL, "jpn1+jpn");


認識結果がこれ。若干認識率がマシになった気がする。。。程度か。
ocr13

以上です。

文字認識(その1)

OCR のライブラリを使って画像の文字を認識してみる。

オープンソースのOCR エンジンの tesseract-ocr を使ってみる。テッセラクトと読むらしい。 google が作っており、以下のページからダウンロードできる。今回は tesseract-3.02.02-win32-lib-include-dirs.zip をダウンロードした。
https://code.google.com/p/tesseract-ocr/downloads/list

zipを解凍すると、include と lib フォルダができるので、プロジェクトのプロパティより、それぞれ「追加のインクルードディレクトリ」と「追加のライブラリディレクトリ」に追加する。

それと、英語用のデータ tesseract-ocr-3.02.eng.tar.gz が必要なのでダウンロードしておく。日本語データの tesseract-ocr-3.02.jpn.tar.gz を使う場合はこれもダウンロードする。

それぞれの zip を解凍すると、tessdata というフォルダが含まれているので、英語用と日本語用をまとめてひとつのフォルダにしておく。この tessdata はプログラム内から指定することになる。

また、tesseract-ocr は、leptoica という画像ライブラリを利用しているため、以下よりライブラリをダウンロードする。今回は leptonica-1.68-win32-lib-include-dirs.zip をダウンロードした。
http://leptonica.com/download.html

こちらもzipを解凍すると、include と lib フォルダができるので、プロジェクトのプロパティより、それぞれ「追加のインクルードディレクトリ」と「追加のライブラリディレクトリ」に追加する。

VC++ のコンソールアプリケーションプロジェクトを作成し、以下の内容で main.cpp を追加する。


#pragma warning(disable:4996)

#include <tesseract/baseapi.h>

#ifdef _DEBUG
#pragma comment(lib, "libtesseract302d.lib")
#pragma comment(lib, "liblept168d.lib")
#else
#pragma comment(lib, "libtesseract302.lib")
#pragma comment(lib, "liblept168.lib")
#endif

#include 
#include 

std::string UTF8toSJIS(const char* src) {

    // UTF8 -> UTF16
    int lenghtUnicode = MultiByteToWideChar(CP_UTF8, 0, src, strlen(src) + 1, NULL, 0);
    wchar_t* bufUnicode = new wchar_t[lenghtUnicode];
    MultiByteToWideChar(CP_UTF8, 0, src, strlen(src) + 1, bufUnicode, lenghtUnicode);

    // UTF16 -> ShiftJis
    int lengthSJis = WideCharToMultiByte(CP_THREAD_ACP, 0, bufUnicode, -1, NULL, 0, NULL, NULL);
    char* bufShiftJis = new char[lengthSJis];
    WideCharToMultiByte(CP_THREAD_ACP, 0, bufUnicode, lenghtUnicode + 1, bufShiftJis, lengthSJis, NULL, NULL);

    std::string strSJis(bufShiftJis);

    delete bufUnicode;
    delete bufShiftJis;

    return strSJis;
}

int main(int argc, char* argv[])
{
    tesseract::TessBaseAPI tess;
    tess.Init("./tessdata", "eng");

    STRING text_out;
    tess.ProcessPages("396px-OCR-A_SP.jpg", NULL, 0, &text_out);

    tesseract::ResultIterator* ri = tess.GetIterator();
    tesseract::PageIteratorLevel level = tesseract::RIL_WORD;

    if (ri != 0) {
        do {
            const char* word = ri->GetUTF8Text(level);
            if (word == NULL || strlen(word) == 0) {
                continue;
            }

            int x1, y1, x2, y2;
            ri->BoundingBox(level, &x1, &y1, &x2, &y2);
            float conf = ri->Confidence(level);

            std::string text = UTF8toSJIS(word);

            printf("(%d, %d)-(%d, %d) : %.1f%% : %s \n", x1, y1, x2, y2, conf, text.c_str());
        } while (ri->Next(level));
    }

    return 0;
}


実行するとコンソールに認識したテキストが表示される。

次の画像で試してみる。
ocr1

こちらが結果。イタリック体と、数字のフォントが変わっているせいか認識が悪い。
ocr2

次に日本語を試す。上のコードで tess.Init に渡している "eng" を "jpn" に変えておく。
読み取る画像はこちら。
ocr3

結果がこれ。
ocr4

認識率は結構ひどい。

以上です。

アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

livedoor 天気