しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

簡単に OCR を行える tesseract-ocr を iOS 7 向けにビルドして実際に動かしてみた

f:id:shiba-yan:20140909155105p:plain

tesseract-ocr - An OCR Engine that was developed at HP Labs between 1985 and 1995... and now at Google. - Google Project Hosting

iOS で OCR を行ってみたかったので、有名な tesseract-ocr を自分でビルドしてみました。Windows はバイナリが提供されていたり、ビルド自体もシンプルだったりしますが、iOS で使う場合には複数のアーキテクチャに対応したライブラリを作る必要があるので手間がかかります。

その辺りの知識が不足していたので、まずは先人の知恵に頼ってビルドしてみることにしました。

Compile tesseract for iOS SDK 6.0 – Code-It

iOS 6 SDK を使ってビルドする手順を書いてくれているページを見つけたので、homebrew を使って必要なツールをインストールして、公開してくれているビルド用スクリプトを使って試してみました.

しかし、公開されているスクリプトでは C/C++ コンパイラが見つからないというエラーになってしまって、ビルドが上手くいきませんでした。

checking build system type... i386-apple-darwin13.3.0
checking host system type... arm-apple-darwin6
checking how to print strings... printf
checking for arm-apple-darwin6-gcc... /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/llvm-gcc
checking whether the C compiler works... no
configure: error: in `/Users/shibayan/Projects/tesseract-build/leptonica-1.71':
configure: error: C compiler cannot create executables

エラーについて調べてみると、既に Objective-C でラップされた Tesseract-OCR iOS というライブラリがあるので、そこで公開されているビルド用スクリプトを使えば上手くいくとあったので試しました。

gali8/Tesseract-OCR-iOS · GitHub

今度はビルドに成功して leptonica と tesseract-ocr のライブラリが無事に生成されましたが、このスクリプトそのままでは stdlibc++ を使ってビルドが行われるらしく、libc++ を使ってビルドされたライブラリとの競合が発生してしまいました。

setenv_all()
{
        # Add internal libs
        ....

        # libc++ を使うように変更
        export CPPFLAGS=$CFLAGS
        export CXXFLAGS="$CFLAGS -stdlib=libc++"
}

CXXFLAGS に -stdlib=libc++ フラグを追加してビルドし直すことで、競合を解決することが出来ました。

実際に iOS で tesseract-ocr を使うサンプルコードを用意しました。tesseract-ocr は C++ なので Objective-C++ で書く必要がある点に注意が必要です。

// TESSDATA_PREFIX 環境変数を定義しておかないと死ぬ
NSString *dataPath = [NSString stringWithFormat:@"%@/", [NSString stringWithString:[[NSBundle mainBundle] bundlePath]]];

setenv("TESSDATA_PREFIX", [dataPath UTF8String], 1);

// OCR エンジンを初期化
tesseract::TessBaseAPI tessBaseApi;

tessBaseApi.Init(nullptr, "eng");

// 対象の画像をセット
tessBaseApi.SetImage(image.data, image.size().width, image.size().height, image.channels(), image.step1());

// 認識
tessBaseApi.Recognize(0);

// OCR 結果を取得
auto result = tessBaseApi.GetUTF8Text();

今回はサンプル画像として抱かれたい男 No.1 の自己紹介が英語でいい感じだったので拾ってきました。

f:id:shiba-yan:20140909161345p:plain

英語のみだとそれなりに認識精度が高そうですね。

次は日本語を試してみます。サンプルとしてかずあきさんの自己紹介を拾ってきました。

f:id:shiba-yan:20140909161838p:plain

うーん、日本語はトレーニングが必要になりそうな精度ですね。所々しか正しく認識出来ていないので、日本語の OCR として使うためにはもう一手間加える必要がありそうです。