2011/05/06

OpenCV×文字認識エンジン

前回、形状マッチングで文字認識をさせようとして見事に失敗した。

しょうがないので、偉大な誰かが作った文字認識エンジンをありがたく使わせていただく事に。

そんなこんなで本日作ったガラクタは、以下のようなカメラ映像から、赤枠内の文字を認識してくれるというシロモノだよ。
こういうものを読み込ませると…。
こんなふうに認識してくれる。



これを作るためにいろいろ探していたら、Tesseract-OCR という文字認識エンジンを見つけたので、さっそくダウンロード。 Windows 環境なら、tesseract-ocr-setup-3.00.exe あたりを落とせば幸せになれると思う。

これを、C:\Program Files\Tesseract-OCR というフォルダにインストール。

使い方は、認識させたい画像を tiff 形式(たとえば tmp.tiff )で保存して、コマンドラインに
tesseract.exe tmp.tiff result
と打ち込む。

すると、自動的に生成されたテキストファイル(result.txt)に結果が書き込まれるのだ。

つまり、ぼくが実装するのは検出対象領域の tiff 画像を作り、tesseract.exe を呼ぶ事くらい。ほとんどオートマチックに実現できてしまう。

#include<cv.h>
#include<cxcore.h>
#include<highgui.h>

#include<fstream>
#include<iostream>
#include<string>

#include<cstdlib>

#pragma comment(lib,"cv200.lib")
#pragma comment(lib,"cxcore200.lib")
#pragma comment(lib,"highgui200.lib")

int main() {

    CvCapture* capture = NULL;
    if((capture = cvCreateCameraCapture(0)) == NULL) 
        return -1;

    cvNamedWindow("カメラ映像", CV_WINDOW_AUTOSIZE);

    IplImage* rgbImg;

    while(1) {

        // ====================
        // カメラからキャプチャ
        // ====================
        rgbImg = cvQueryFrame(capture);

        // 識別対象枠の表示
        int fieldSize = (int)(rgbImg->height * 0.9);
        cvRectangle(rgbImg,
            cvPoint(    
                (rgbImg->width  - fieldSize) / 2 -1,
                (rgbImg->height - fieldSize) / 2 -1),
            cvPoint(
                (rgbImg->width  + fieldSize) / 2 +1,
                (rgbImg->height + fieldSize) / 2 +1),
            cvScalar(0, 0, 255));

        cvShowImage("カメラ映像", rgbImg);

        // =======
        // ROI設定
        // =======
        cvSetImageROI(rgbImg, 
            cvRect((rgbImg->width - fieldSize) / 2, 
                   (rgbImg->height - fieldSize) / 2, 
                fieldSize, fieldSize));

        
        int key = cvWaitKey(33);
        // ===========================
        // Sキーが押されたら、文字認識
        // ===========================
        if (key == 's') {
            cvSaveImage("test.tiff", rgbImg);
            
            // コマンド実行(結果はtmp.txtに保存)
            system("\"C:\\Program Files\\Tesseract-OCR\\tesseract.exe\" test.tiff tmp");
            system("cls");

            // tmp.txtの内容を表示
            std::ifstream ifs("tmp.txt");
            std::string str;
            ifs >> str;
            std::cout << "「" << str <<
                "」…と、検出されました。" << std::endl;

        }

        cvResetImageROI(rgbImg);
        if (key == 'q') break;
    }

    cvReleaseCapture(&capture);
    cvReleaseImage(&rgbImg);

    cvDestroyWindow("カメラ映像");

    return 0;
}

操作方法は、対象物を写しつつ s キーを押すだけ。

すると、赤枠内の対象領域が test.tiff として保存され、tesseract.exe が呼ばれる。

保存された「test.tiff

検出した文字は std::string オブジェクトに格納されるので、煮るなり焼くなりし放題だ(今回は単に表示しただけ)。


前回よりだいぶマシになったものの、残念ながら精度はまだ満足いくものではない(誤検出がけっこう多い)。

さらに前処理などを加える事で改善できそうな気もするけれど、ちょっと骨が折れそうなのでまた今度。

4 件のコメント:

  1. こういう組合せ方ができるんですね!大変参考になりました

    返信削除
  2. コメントありがとうございます。非常に励みになります。

    CUI アプリケーションならではの“部品としてプログラムに組み込みやすい”という利点に、興味を抱いて頂けたら幸いです。

    返信削除
  3. Tesseractをダウンロードしてインストールしましたが、どの.exeファイルを実行してもコマンド窓が出ないのです。どうすればいいんですか?

    返信削除
  4. 大変参考にさせていただいております。ありがとうございます。

    日本語でOCRをする場合、どのように記述すれば実行できるでしょうか。
    日本語の言語ファイルはインストールしています。

    御手数ですが、よろしくお願いします。

    返信削除

ひとことどうぞφ(・ω・,,)