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

認識率は結構ひどい。

以上です。