OCRベースの会計システム

プロローグ



彼の経歴の中で、彼は広告情報の会計システムを発明し、実行するタスクを受け取りました。 会計は、適切な掲示板で適切な情報の可用性をチェックすることでした。 シールドと印刷には番号が付けられています。

システムの初期情報として写真を使用することが提案されました。 デザイナーとの貿易協定の後、両方の番号が同じフレーム内に配置されることに合意しました。 フレームがシールド上のどこにでもあることができる唯一のもの。

実際、問題の説明はこれで終わり、実装の物語が始まります。

問題は3つのアクションで解決されます。

  1. 画像から目的の長方形を見つけます。
  2. テキスト認識。
  3. 認識の検証。




アクション1-検索



画像内の目的の長方形を見つけるための最も簡単な方法は、長方形と呼ぶことができるすべてのピースを見つけ、特定のパラメーターに従ってフィルターすることです。 画像内の四角形を検索するために、OpenCVのわずかにドープされた標準例を使用しました。squares.cppから四角形の検索機能を取得しました。

パターン検索手順は非常に原始的であり、入力に多くの色の境界線と遷移がある複雑な画像がある場合、一連の長方形が得られますが、その中で、認識手順の前でも不要なものを捨てる必要があります。



不要なものは、いくつかの基準によってフィルタリングされます。

1.幅と高さの比率。

プログラムにはカットオフ基準(r.width <5 * r.height)があり、改善でき、デルタを含む条件条件をより正確に使用できます。

ここでの主なことは、カメラマンが想像力を発揮せず、カメラを90度回転させて被写体を撮影しないことです(足で私を撮影します)。

2.ほぼ同じ形状を削除します。



もう1つのポイント:フィルタリングの前に、写真家の手がひるむことがあり、目的の長方形が写真内で水平方向に垂直でない境界線を持つ場合があるため、長方形をまっすぐにします。



次に、組み立てられたすべての長方形をファイルに切り取ります。

認識ユーティリティが白黒画像をより適切に処理することが実験的に確立されました。そのため、ファイルに書き込む前にcvAdaptiveThresholdメソッドが呼び出されます。 変換手順のブロックサイズは実験的に選択されました。



<source lang="cpp"> #include "cv.h" #include "highgui.h" #include <iostream> #include <math.h> #include <string.h> #include <stdio.h> using namespace cv; using namespace std; typedef vector<Point> polygon; typedef vector<polygon> polygonList; ... //     bool compareRect(const CvRect &r1, const CvRect &r2) { if (!r1.width || !r1.height) return false; if ((float)abs(r1.width- r2.width)/(float)r1.width > 0.05) return false; if ((float)abs(r1.height - r2.height)/(float)r1.height > 0.05) return false; if ((float)abs(r1.x - r2.x)/(float)r1.width > 0.02) return false; if ((float)abs(r1.y - r2.y)/(float)r1.height > 0.02) return false; return true; } //  CvRect getRect(const polygon& poly) { CvPoint p1 = cvPoint(10000,10000); CvPoint p2 = cvPoint(-10000,-10000); for (size_t i=0; i < poly.size(); i++) { const Point p = poly[i]; if (p1.x > px) p1.x = px; if (p1.y > py) p1.y = py; if (p2.x < px) p2.x = px; if (p2.y < py) p2.y = py; } return cvRect(p1.x,p1.y,p2.x-p1.x,p2.y-p1.y); } int main(int argc, char** argv) { if(argc <= 3) { cout << "Wrong Param Count: " << argc << endl; cout << "Usage: findrect infile extension outfolder" << endl; return 1; } char *fileIn = argv[1]; char *fileExt = argv[2]; char *dirOut = argv[3]; char fileOut[128]; polygonList squares; IplImage *Img = cvLoadImage(fileIn,1); Mat image(Img); if(image.empty()) { cout << "Couldn't load " << fileIn << endl; return 1; } findSquares(image, squares); vector<CvRect> rectList; int p = 0; int adaptive_method = CV_ADAPTIVE_THRESH_GAUSSIAN_C; int threshold_type = CV_THRESH_BINARY; int block_size = 65; double offset = 10; for (int j=0; j<squares.size(); j++) { //  CvRect r = getRect(squares[j]); if (r.width < 5*r.height) continue; //     bool doContinue = false; for (int k=0; k<rectList.size(); k++) if (compareRect(r, rectList[k])) { doContinue = true; break; } if (doContinue) continue; rectList.push_back(r); //     cvSetImageROI(Img, r); IplImage *dst = cvCreateImage(cvSize(r.width, r.height), Img->depth, Img->nChannels); IplImage *gray = cvCreateImage(cvSize(r.width, r.height), 8, 1); IplImage *bw = cvCreateImage(cvSize(r.width, r.height), 8, 1); cvCopy(Img, dst, NULL); cvResetImageROI(Img); //   ,        php sprintf(fileOut,"%s/%d.%s",dirOut, p, fileExt); cout << fileOut << endl; p++; //  - cvCvtColor(dst,gray,CV_RGB2GRAY); cvAdaptiveThreshold(gray, bw, 255, adaptive_method,threshold_type,block_size,offset); cvSaveImage(fileOut, bw); cvReleaseImage(&dst); cvReleaseImage(&gray); cvReleaseImage(&bw); } return 0; }
      
      







2番目のアクションは認識です



認識ユーティリティは、入力で通常のコンテンツとゴミの両方を受け取ります。

画像



画像



画像



画像



前述のように、認識にはGoogleのユーティリティ-tesseractを使用します。

他の認識ツールも使用できますが、cuniformもテストされました。

しかし、tesseractは、多くの情報があり、独自の文字セットでトレーニングするためのわかりやすい指示があったという事実のために選択されました。



アルファベットのトレーニングは、いくつかの目標で行われました。

  1. 数字を認識するための辞書-10文字で構成する必要があり、文字やその他の文字は必要ありません。 短いセットのエラー確率。
  2. 原則として、1日目は停止することができました-tesseractには数字のみを認識するモードがあります。 独自の辞書を作成せずに使用できます。

    しかし、テスト結果はもう1つのアイデアを動かしました。理由は次のとおりです。通常のフォント(標準セットに含まれる)は、OCRの観点から数字の文字が互いに類似しています。 「To」8」など

    したがって、数字の記号が互いに類似しないフォントを使用することが決定されました。 フォントを見つけるためのヒントとして、その名前-「OCR A Std」がありました。 このフォントは、上記のクリッピングで使用されます。

    したがって、エラーの可能性を減らす別の要因があります。



その結果、このフォントの10文字の辞書がtesseract用に作成され、上記の切り抜きで見ることができます。

ユーティリティをトレーニングするための指示は行いません。プロセスは創造的でも機械的でもありません。ネットワークには多くの指示があります。



アクション3-集合



システムはUbuntuでテストされました。 スライスおよび認識ユーティリティの実行は、phpによって実行されます。

ここで、認識されたデータの最終検証は、チェックサム方式を使用して実行されます。

crc-8アルゴリズムが使用されます。

 $imagesout = '/home/toor/www/out'; $findrect = '/home/toor/OCR/OpenCV-2.2.0/samples/cpp/findrect'; $uploaddir = '/home/toor/www/uploads/'; $rectdir = '/home/toor/www/out/'; $tesseract = '/home/toor/OCR/tesseract-3.00/api/tesseract'; ... if (isset($_FILES['userfile']['tmp_name'])) { $uploadfile = $uploaddir. $_FILES['userfile']['name']; if (!move_uploaded_file($_FILES['userfile']['tmp_name'], $uploaddir . $_FILES['userfile']['name'])) { echo " !"; exit(1); } echo " {$_FILES['userfile']['name']}  !"; $cmd = "$findrect $uploadfile tif $imagesout"; exec($cmd, $output); echo count($output)." "; $datas = array(); foreach($output as $k => $f) { $recognized = "$rectdir$k.txt"; $cmd = "$tesseract $f $rectdir$k -l nums.ocr"; exec($cmd); if (!file_exists($recognized)) continue; echo "file: $recognized"; $data = file_get_contents($recognized); $data = preg_replace('/\D/','',$data); $data = trim($data); if (!strlen($data)) continue; if (!array_key_exists($data,$datas)) $datas[$data] = 1; else $datas[$data]++; } foreach ($datas as $d => $v) { if ($r = crc_check($d, NUMBER_LEN_1, NUMBER_LEN_CRC_1)) { echo ' : '.$r; } if ($r = crc_check($d, NUMBER_LEN_2, NUMBER_LEN_CRC_2)) { echo ' : '.$r; } } }
      
      







一般に、テストモードでは、システムは非常に良好であることが証明されました。

このような最も単純な携帯電話からの画像が作成されています



デジタルカメラでは最大数メガバイトです。



参照資料



テッセラクト

Opencv

OCR A Stdフォント



All Articles