株式会社インデペンデンスシステムズ横浜

システム開発エンジニアの西田五郎が運営しております。Raspberry Pi や Arduino その他新規開発案件のご依頼をお待ちしております。

OpenCV Tesseract-OCR

Tesseract-OCRの導入(その3)OpenCVの出力を認識する

投稿日:2014年11月24日 更新日:

2019/07/20追記
この記事を書いてから随分と経過しました。完全に情報が古くなっています。外部のサイトですが必要な場合は以下等を参照して下さい。
PythonとTesseract OCRで文字認識
OpenCVのOCR(tesseract-ocr)をWindows(64bit)、C++で使う
vcpkgとCMakeで簡単にtesseract-ocr
2019/07/20追記ここまで

Tesseract-OCRの導入の3回目です。前回はvc++のコンソールアプリからAPIを使ってみました。今回も同じような使い方ですが、OpenCVでの領域の認識結果をTesseract-OCRのAPIで文字を認識するという流れです。(※OpenCV 3.0系からは文字認識が組み込まれるようです。今回のTesseract-OCRもOpenCVに組み込まれるようです。詳細はページ最後の関連サイト等を参照して下さい。)

今回の処理の流れです。以下のような何となくそれらしい入力用紙をイメージした画像を作成しました。作成したのはExcelでそのスクリーンショットを切り取って保存しました。
InputForm1

まずここからOpenCVで入力領域を切り出します。
0013

0011

これらをそれぞれTesseract-OCRの入力ファイルとして認識します。以下のように結果が表示されました。
0014

0015

ここからプログラムの説明です。ペースになっているプログラムは以下で作成したプログラムです。
OpenCVで輪郭抽出から隣接領域の切り出し(その1)輪郭抽出まで

このプログラムのプロジェクトに前回までに書いた環境でTesseract-OCRのAPIを使います。前回書いたライブラリのインクルードディレクトリやライブラリファイルの設定も今回のプロジェクトに追加します。

ここまでをベースにして以下のようなプログラムを作成しました。

※ソース全体は以下からダウンロード出来ます。Tesseractのインストール、ライブラリの設定が必要です。必要な場合は前回までを参照して下さい。
プロジェクト一式
(※必要な場合は用途に限らずご利用頂いて問題ありませんが、一切無保証です。弊社は一切の責任を負いません。)

/*------------------------------------------------
 処理1
-------------------------------------------------*/
void func1(HWND hWnd)
{
	////MessageBox(hWnd, "func1", "debug", MB_OK);
	if (imgMatRead.rows == 0){
		MessageBox(hWnd, "画像ファイルが無効です", "エラー", MB_OK);
		return;
	}

	//入力画像、ここでは毎回ファイルから読み込む
	cv::Mat imgIn = cv::imread((const std::string&)szOpenFileName, 1); //3チャンネルカラー画像で読み込む;

	//グレースケール
	cv::Mat grayImage, binImage;
	cv::cvtColor(imgIn, grayImage, CV_BGR2GRAY);
	
	//2値化(※反転で結果が変わる、基本は背景が黒で物体が白)
	//ここでは固定のしきい値を使用する
	cv::threshold(grayImage, binImage, 220, 255.0, CV_THRESH_BINARY);
	//cv::imshow("bin", binImage);

	//輪郭の座標リスト
	std::vector< std::vector< cv::Point > > contours;

	//輪郭取得
	cv::findContours(binImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

	//輪郭の数
	int roiCnt = 0;

	//輪郭のカウント	
	int i = 0;

	for (auto contour = contours.begin(); contour != contours.end(); contour++){

		std::vector< cv::Point > approx;
		
		//輪郭を直線近似する
		cv::approxPolyDP(cv::Mat(*contour), approx, 0.01 * cv::arcLength(*contour, true), true);
		
		// 近似の面積が一定以上なら取得
		double area = cv::contourArea(approx);

		if (area > 1000.0){				
			//輪郭に隣接する矩形の取得
			cv::Rect brect = cv::boundingRect(cv::Mat(approx).reshape(2));
			roi[roiCnt] = cv::Mat(grayImage, brect);
			
			//表示
			cv::imshow("label" + std::to_string(roiCnt+1), roi[roiCnt]);

			if (roiCnt == 0){
				imgMatWrite = roi[roiCnt];
			}
		
			roiCnt++;

			//念のため輪郭をカウント
			if (roiCnt == 99)
			{
				break;
			}
		}
		i++;
	}

	//ここからTesseractの処理
	const int charSize = 1024;

	char szTmpPath[charSize];	//作業用ディレクトリ

	char userid[charSize];	//ユーザID
	char name[charSize];	//名前
	char msg[charSize];		//メッセージボックス用

	//認識対象画像を一時的に保存するディレクトリを取得する
	GetTempPath(sizeof(szTmpPath) / sizeof(szTmpPath[0]),szTmpPath);
	strcat(szTmpPath, "\\ocrimg.png");

	//Tesseract初期化
	tesseract::TessBaseAPI tess;
	tess.Init("", "eng", tesseract::OEM_DEFAULT);

	//対象画像ごとの処理
	for (int i = 0; i < roiCnt; i++){

		//一時ファイルに保存
		imgMatWrite = roi[i];
		cv::imwrite(szTmpPath, imgMatWrite);

		//認識開始
		STRING text;
		tess.ProcessPages(szTmpPath, NULL, 0, &text);

		//認識結果の取得
		const char* result = text.string();
		
		//ユーザIDの場合
		if (strncmp(result, "UserID", 6) == 0){
			memset(userid, 0x00, 1024);
			strncpy(userid, result + 6, strlen(result) - 6 - 2);	//2は改行コードの長さ

			sprintf(msg, "ユーザIDは、%s です。", userid);
			MessageBox(hWnd, msg, "結果", MB_OK);
		}

		//名前の場合
		if (strncmp(result, "Name", 4) == 0){
			memset(name, 0x00, 1024);
			strncpy(name, result + 4, strlen(result) - 4 - 2);		//2は改行コードの長さ

			sprintf(msg, "名前は、%s です。", name);
			MessageBox(hWnd, msg, "結果", MB_OK);
		}
	}

	//念のため
	tess.Clear();
	tess.End();
}

上記ソースは認識の部分のみです。全体が必要な場合はお手数ですがソース一式をダウンロードして参照して下さい。OpenCVの輪郭の認識のプログラムにTesseract-OCRのAPIでの認識を後付けしたような処理ですが以下のようの流れです。

OpenCVで認識出来た輪郭をグレースケールの画像から輪郭画像の配列に保存

輪郭ごとに一時ファイルに保存

一時ファイルをTesseract-OCRで英数字で認識

あらかじめ決めたユーザIDと名前のキーワードがあればユーザID、名前として認識して表示する

OpenCVからTesseract-OCRへは単純にファイルで渡しています。また文字列操作はC言語の関数で処理しています。

まあこれぐらいなら認識出来ましたが日本語も含めてどこまで認識出来るかということになってくると思います。そういった意味でもいろいろと課題があると思いますがとりあえず今回のシリーズとしてはここまでです。

関連サイト
Advanced API
opencvで文字認識その1 Tesseractラッパ – whoopsidaisies’s diary

関連書籍
(※OpenCV 2 プログラミングブックは私も持っています。)

(※ここからはKindle版で英語ですが最新の情報もあるようです。また価格的にはいいかもしれないです。)


AdSense

AdSense

-OpenCV, Tesseract-OCR

執筆者:

関連記事

OpenCVをWin32ベースで利用する(その3)カメラ入力からの画像処理

OpenCVをWin32ベースで利用するの3回目です。前回は画像ファイルを入力にしてその画像に対してOpenCVで画像処理を行うというプログラムでした。今回は大きくは変わらないですが、カメラからの画像 …

Visual Studio Community 2013のVisual C++でOpenCVを使う

Visual Studio Community 2013のVisual C++でOpenCVを使う方法についてです。Visual Studio Community 2013については前回書きましたが、 …

OpenCVで輪郭抽出から隣接領域の切り出し(その3)凸包の取得

OpenCVで画像内の輪郭抽出からその輪郭の隣接領域(四角形)を求めてその領域を切り出すという処理を作ってみました。前回までのプログラムとほぼ同じですが、前回までは輪郭抽出 → 直線近似 → 隣接領域 …

OpenCV2 cv::Matクラスの基礎

OpenCV2のcv::Matクラスの基礎についてです。OpenCV 2.0からはC++のインターフェースが追加されました。cv::MatクラスはそのC++インターフェースで画像を扱うクラスです。まず …

OpenCVをWin32ベースで利用する(その2)OpenCVの組み込み

OpenCVをWin32ベースで利用するの2回目です。前回はベースになるダイアログベースのアプリケーションを作成しました。今回はこのアプリケーションにOpenCVを組み込んで実際に動かしてみます。 ( …