Tesseract OCRで数字の認識
オープンソースで最も認識精度が高いと言われている文字認識エンジン、Tesseractで数字を認識してみる。名刺の中の電話番号を認識する、という想定。OSはMac OS X.
画像の準備
名刺っぽいプリントアウトをスマホのカメラで撮影。 画像サイズは2592x1944. 人名や住所などは全くデタラメw
tesseractのインストール
tesseractをMacPortsでインストール。
sudo port install tesseract
ソースコード
処理の流れとして、まず二値化を行い、次に文字認識を適用する。文字認識結果の出力とは別に、二値化の結果画像もtifファイルとして保存する。
文字認識では、数字といくつかの記号をホワイトリストとしている。なので、後に見るように、漢字やアルファベットなども無理やり数字として解釈してしまう。
認識結果の一文字ごとに確信度(confidence)が割り当てられる。認識結果を出力する際は、確信度が高いものと低いものを区別して出力する。低いものにはインデントを付けて出力する。
#include <iostream> #include <cstdlib> #include <tesseract/baseapi.h> #include <leptonica/allheaders.h> using namespace std; using namespace tesseract; int main(int argc, char **argv) { if(argc != 3){ cerr << "USAGE: " << argv[0] << " /path/to/image /path/to/bi-output-image" << endl; exit(1); } char* src = argv[1], *bi = argv[2]; // // 入力画像を二値化する // PIX *pixsrc = pixRead(src); PIX *pixgray = pixConvertRGBToLuminance(pixsrc); // グレイスケールに一度変換 PIX *pixbi = pixCreate(pixgray->w, pixgray->h, 2); // 二値化 pixOtsuAdaptiveThreshold(pixgray, pixgray->w, pixgray->h, 0, 0, 0.1, NULL, &pixbi); pixWrite(bi, pixbi, IFF_TIFF); // 要らないものをfinalize pixDestroy(&pixsrc); pixDestroy(&pixgray); // // 文字認識実行 // TessBaseAPI tess; if(tess.Init(NULL, "eng")){ cerr << "could not initialize tesseract" << endl; exit(1); } tess.SetVariable("save_blob_choices", "T"); // ホワイトリスト設定 tess.SetVariable("tessedit_char_whitelist", "0123456789 -:()"); tess.SetImage(pixbi); tess.Recognize(NULL); ResultIterator* ri = tess.GetIterator(); if(ri != 0){ // 一文字ずつ結果を見ていく do { const char* symbol = ri->GetUTF8Text(RIL_SYMBOL); if(symbol != 0){ float conf = ri->Confidence(RIL_SYMBOL); // 認識結果と確信度を出力 if(conf < 80) // 確信度が低ければインデントを付与 cout << " \'" << symbol << "\'" << " confidence: " << conf << endl; else cout << "\'" << symbol << "\'" << " confidence: " << conf << endl; // ChoiceIterator ci(*ri); // do { // const char* choice = ci.GetUTF8Text(); // cout << "\t\t\t" << "\'" << choice << "\': " // << ci.Confidence() << endl; // } while(ci.Next()); } delete[] symbol; } while((ri->Next(RIL_SYMBOL))); } tess.Clear(); tess.End(); pixDestroy(&pixbi); return 0; }
ビルド
g++ -o tess tess.cpp -O2 -I/opt/local/include -L/opt/local/lib -llept -ltesseract
実行
第一引数に入力画像を、第二引数に保存する二値化画像のファイル名を与える。結果は以下のとおり。
$ ./tess cap.jpg cap.tif '3' confidence: 55.7878 '5' confidence: 48.2515 '1' confidence: 74.4947 '2' confidence: 74.8571 '9' confidence: 65.7379 '4' confidence: 50.08 '0' confidence: 13.8199 '3' confidence: 66.5101 '0' confidence: 22.5098 '0' confidence: 6.99005 '0' confidence: 91.9207 '8' confidence: 93.2891 '5' confidence: 91.6527 '-' confidence: 94.7043 '0' confidence: 90.4132 '0' confidence: 91.5067 '3' confidence: 95.2874 '2' confidence: 92.9869 '1' confidence: 64.2396 '0' confidence: 49.9588 '5' confidence: 69.2291 '0' confidence: 16.5115 '5' confidence: 54.0336 '1' confidence: 63.1991 '5' confidence: 52.3447 '3' confidence: 56.4374 '1' confidence: 74.0782 '0' confidence: 44.8059 '0' confidence: 51.2802 '5' confidence: 56.8292 '5' confidence: 50.2101 '0' confidence: 58.1238 '0' confidence: 23.41 '0' confidence: 51.4877 '5' confidence: 67.2946 '0' confidence: 29.2511 '0' confidence: 41.8625 '0' confidence: 45.2179 '1' confidence: 73.9682 '7' confidence: 93.7799 '-' confidence: 96.4489 '1' confidence: 88.6481 '4' confidence: 91.9315 '-' confidence: 93.9458 '9' confidence: 90.9804 '0' confidence: 20.1172 '1' confidence: 69.0272 ':' confidence: 95.3482 '0' confidence: 88.9497 '1' confidence: 94.7421 '5' confidence: 91.4299 '4' confidence: 93.6259 '-' confidence: 96.483 '9' confidence: 90.8426 '7' confidence: 94.9449 '-' confidence: 90.6047 '4' confidence: 91.5667 '8' confidence: 90.4304 '9' confidence: 88.8301 '8' confidence: 94.6282 '0' confidence: 69.7327 '0' confidence: 64.6164 '1' confidence: 70.6974 '0' confidence: 67.1356 '0' confidence: 56.4117 ':' confidence: 92.6204 '1' confidence: 70.3545 '(' confidence: 79.365 '3' confidence: 73.291 '0' confidence: 28.9734 '5' confidence: 70.0992 '0' confidence: 57.6477 '0' confidence: 30.6046 '0' confidence: 74.5287 '5' confidence: 82.144 '0' confidence: 74.3088 '0' confidence: 72.9004 '0' confidence: 50.3754 '6' confidence: 51.6748 '0' confidence: 76.4664 '0' confidence: 16.0721 '0' confidence: 76.0345 '6' confidence: 68.1494 '0' confidence: 19.3069 '1' confidence: 64.2986 '0' confidence: 1.06659 '0' confidence: 75.0809
インデントされているのは確信度が80よりも小さい文字。名刺の中の漢字やアルファベットは、ほとんどが80より小さくなっている。逆に、数字の認識はいずれも確信度が高く、実際にすべて成功している。
従って、確信度の高いチャンクを切り出し、電話番号のフォーマットに合致しているものを取り出せば、今回は電話番号を特定できたことになる。
ちなみに以下が二値化された画像。良好に二値化されている。