2012-02-22 4 views
9

クレジットカードの数字を認識したい。状況を悪化させるために、ソース画像は高品質であるとは保証されません。 OCRはニューラルネットワークを介して実現されるが、ここでは話題ではない。OCR用の複雑な画像を準備する

現在の問題は画像の前処理です。クレジットカードには背景やその他の複雑なグラフィックスがあるため、文書をスキャンするほど明瞭ではありません。私はエッジ検出(Canny Edge、Sobel)で実験を行いましたが、成功しませんでした。 また、グレースケール画像とぼかし画像(Remove background color in image processing for OCR)の違いを計算しても、OCRableの結果は得られませんでした。

特定の数字とその背景のコントラストが十分強くないため、ほとんどのアプローチが失敗すると思います。おそらく、画像をブロックに分割して、各ブロックに最適な前処理ソリューションを見つける必要がありますか?

ソースを読み込み可能なバイナリイメージに変換する方法はありますか? エッジの検出は基本的な色の閾値処理ですか?

オリジナル画像:

Original image

グレースケール画像:

ここ

は(私は結果で明らかに満足していない)グレースケール判定閾値アプローチのサンプルです

Greyscale image

しきい値画像:どんなアドバイスを

Thresholded image

おかげで、 バレンティン

+0

コントラストがあまりないので、私が述べたようにエッジ検出を試みます。 –

答えて

5

可能であれば、より良い照明を使用して画像をキャプチャするようにリクエストしてください。ローアングルライトは、盛り上がった(または沈んだ)文字のエッジを照らし、画質を大幅に改善します。イメージが機械によって分析されることを意図されている場合、照明は機械可読性のために最適化されるべきである。

しかし、あなたが調べなければならないアルゴリズムの1つは、自然画から文字を抽出するために使用されるストローク幅変換です。

Stroke Width Transform (SWT) implementation (Java, C#...)

グローバルしきい値(二値化のためか、エッジ強度をクリッピング)おそらく、このアプリケーションのためにそれをカットされません、代わりにあなたがローカライズされたしきい値をご覧ください。あなたのサンプル画像では、 "31"に続く "02"は特に弱いので、単一の閾値を使って文字列のすべてのエッジをフィルタリングするよりも、その領域で最も強いローカルエッジを探す方が良いでしょう。

文字の部分的なセグメントを識別できる場合は、方向性のモルフォロジー操作を使用してセグメントを結合することができます。あなたは0が背景と1がフォアグラウンドである次のような2つのほぼ水平のセグメントを、持っている場合たとえば、...

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 1 1 1 1 0 0 1 1 1 1 1 1 0 0 0 
0 0 0 1 0 0 0 1 0 1 0 0 0 0 1 0 0 0 

は、あなただけに、水平方向に沿って、形態素「クローズ」操作を行うことができこれらのセグメントに参加します。カーネルは、より洗練された方法は、ベジェを使用して曲線補完を実行するためにあります

x x x x x 
1 1 1 1 1 
x x x x x 

ようなものになる可能性が収まるかさえオイラーは(別名クロソイド)スパイラルが、参加する貧困層を排除するために参加するセグメントおよび後処理を識別するために前処理することは得ることができます非常にトリッキー。私の実装で

5

私が問題に取り掛かるだろうか方法が異なるセクションにカードを別のものです。 (MasterCard、Visa、のリストはあなた次第です)から始まるユニークなクレジットカードはあまりありません。したがって、クレジットカードを指定するためのドロップダウンのようにすることができます。そのようにして、排除し、画素領域を指定することができる:

例:

だけ下から20個のピクセルは、 から30個のピクセルは右から10個のピクセルに左領域と連携底( 矩形を作成する)から30個の画素 - これは私は、画像のコントラストを上げてグレースケールにそれを変換(楽しいプロジェクト)画像処理プログラムと協力

は、かかったすべてのマスターカードをカバーしますアヴェンジャ1つのピクセルの個々のRGB値のGE、およびすべての画素の周りにそれを比較した:

例:

PixAvg[i,j] = (Pix.R + Pix.G + Pix.B)/3 
if ((PixAvg[i,j] - PixAvg[i,j+1])>30) 
    boolEdge == true; 

30はあなたのイメージになりたいどのように異なるだろう。差が小さいほど、許容誤差が小さくなります。

私のプロジェクトでは、エッジ検出を表示するために、boolEdgeの値とピクセル配列を含むブール値の別々の配列を作成しました。画素アレイは、白黒のドットだけで満たされていた。 boolean配列から値を取得します。ここで、boolEdge = trueは白い点、boolEdge = falseは黒い点です。したがって、最終的には、白と黒の点だけを含むピクセル配列(完全な画像)になります。

そこから、番号の開始位置と終了位置を検出する方がずっと簡単です。

1

は、私はここからのコードを使用しようとしました:http://rnd.azoft.com/algorithm-identifying-barely-legible-embossed-text-image/ 結果が良くなく、十分ではありません... は、私はそれが硬い質感カードの右のparamsを見つけるために見つけます。

(void)processingByStrokesMethod:(cv::Mat)src dst:(cv::Mat*)dst { 
cv::Mat tmp; 
cv::GaussianBlur(src, tmp, cv::Size(3,3), 2.0);     // gaussian blur 
tmp = cv::abs(src - tmp);           // matrix of differences between source image and blur iamge 

//Binarization: 
cv::threshold(tmp, tmp, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); 

//Using method of strokes: 
int Wout = 12; 
int Win = Wout/2; 
int startXY = Win; 
int endY = src.rows - Win; 
int endX = src.cols - Win; 

for (int j = startXY; j < endY; j++) { 
    for (int i = startXY; i < endX; i++) { 
     //Only edge pixels: 
     if (tmp.at<unsigned char="">(j,i) == 255) 
     { 
      //Calculating maxP and minP within Win-region: 
      unsigned char minP = src.at<unsigned char="">(j,i); 
      unsigned char maxP = src.at<unsigned char="">(j,i); 
      int offsetInWin = Win/2; 

      for (int m = - offsetInWin; m < offsetInWin; m++) { 
       for (int n = - offsetInWin; n < offsetInWin; n++) { 
        if (src.at<unsigned char="">(j+m,i+n) < minP) { 
         minP = src.at<unsigned char="">(j+m,i+n); 
        }else if (src.at<unsigned char="">(j+m,i+n) > maxP) { 
         maxP = src.at<unsigned char="">(j+m,i+n); 
        } 
       } 
      } 

      //Voiting: 
      unsigned char meanP = lroundf((minP+maxP)/2.0); 

      for (int l = -Win; l < Win; l++) { 
       for (int k = -Win; k < Win; k++) { 
        if (src.at<unsigned char="">(j+l,i+k) >= meanP) { 
         dst->at<unsigned char="">(j+l,i+k)++; 
        } 
       } 
      } 
     } 
    } 
} 

///// Normalization of imageOut: 
unsigned char maxValue = dst->at<unsigned char="">(0,0); 

for (int j = 0; j < dst->rows; j++) {    //finding max value of imageOut 
    for (int i = 0; i < dst->cols; i++) { 
     if (dst->at<unsigned char="">(j,i) > maxValue) 
      maxValue = dst->at<unsigned char="">(j,i); 
    } 
} 
float knorm = 255.0/maxValue; 

for (int j = 0; j < dst->rows; j++) {    //normalization of imageOut 
    for (int i = 0; i < dst->cols; i++) { 
     dst->at<unsigned char="">(j,i) = lroundf(dst->at<unsigned char="">(j,i)*knorm); 
    } 
} 
+0

良い、あなたはリンクを提供した、あまりにもOPのためのいくつかの説明を提供してください。 – Yahya

関連する問題