2

データベースに事前に保存したすべての文字を使用して、画像から抽出された文字間の係数相関を計算することにより、OCR を構築しようとしています。私の実装はJavaに基づいており、事前に保存された文字はアプリケーションの開始時にArrayListにロードされます。

ArrayList<byte []> storedCharacters, extractedCharacters;
storedCharacters = load_all_characters_from_database();
extractedCharacters = extract_characters_from_image();

// Calculate the coefficent between every extracted character
// and every character in database.
double maxCorr = -1;
for(byte [] extractedCharacter : extractedCharacters)
  for(byte [] storedCharacter : storedCharactes)
  {
     corr = findCorrelation(extractedCharacter, storedCharacter)
     if (corr > maxCorr)
       maxCorr = corr;
  }
...
...
public double findCorrelation(byte [] extractedCharacter, byte [] storedCharacter)
{
  double mag1, mag2, corr = 0;
  for(int i=0; i < extractedCharacter.length; i++)
  {
     mag1 += extractedCharacter[i] * extractedCharacter[i];
     mag2 += storedCharacter[i] * storedCharacter[i];
     corr += extractedCharacter[i] * storedCharacter[i];
  } // for
  corr /= Math.sqrt(mag1*mag2);
  return corr;
}

抽出された文字の数は画像ごとに約 100 ~ 150 ですが、データベースには 15600 のバイナリ文字が格納されています。Intel i5 CPU では、抽出されたすべての文字と保存されたすべての文字の間の係数相関をチェックすると、すべての画像を完了するのに約 15 ~ 20 秒かかるため、パフォーマンスに影響します。このプログラムの速度を改善する方法はありますか、またはこれを構築する別の方法を提案して同様の結果をもたらします。(すべての文字をそのような大規模なデータセットと比較することによって得られる結果は非常に優れています)。

前もって感謝します

更新 1

public static void run() {
    ArrayList<byte []> storedCharacters, extractedCharacters;
    storedCharacters = load_all_characters_from_database();
    extractedCharacters = extract_characters_from_image();
    
    // Calculate the coefficent between every extracted character
    // and every character in database.
    computeNorms(charComps, extractedCharacters);       
    double maxCorr = -1;
    for(byte [] extractedCharacter : extractedCharacters)
      for(byte [] storedCharacter : storedCharactes)
      {
         corr = findCorrelation(extractedCharacter, storedCharacter)
         if (corr > maxCorr)
           maxCorr = corr;
      }
    }
}
private static double[] storedNorms;
private static double[] extractedNorms;
       
// Correlation  between to binary images
public static double findCorrelation(byte[] arr1, byte[] arr2, int strCharIndex, int extCharNo){
         final int dotProduct = dotProduct(arr1, arr2);
         final double corr = dotProduct * storedNorms[strCharIndex] * extractedNorms[extCharNo];
         return corr;
}
    
public static void computeNorms(ArrayList<byte[]> storedCharacters, ArrayList<byte[]> extractedCharacters) {
          storedNorms = computeInvNorms(storedCharacters);
          extractedNorms = computeInvNorms(extractedCharacters);
}
    
private static double[] computeInvNorms(List<byte []> a) {
         final double[] result = new double[a.size()];
         
         for (int i=0; i < result.length; ++i) 
            result[i] = 1 / Math.sqrt(dotProduct(a.get(i), a.get(i)));
         return result;
}
      
private static int dotProduct(byte[] arr1, byte[] arr2) {
         int dotProduct = 0; 
         for(int i = 0; i< arr1.length; i++)
            dotProduct += arr1[i] * arr2[i];
          
         return dotProduct;
}
4

1 に答える 1

0

現在、シングルコアの CPU を見つけるのは困難です (モバイルでも)。タスクがうまく分離されているため、数行で実行できます。だから私はそれに行きますが、利益は限られています。

相互相関を本当に意味する場合は、DFTDCTなどの変換が役立ちます。確かに大きな画像には適していますが、あなたの 12x16 ではわかりません。

多分あなたはただの内積を意味しますか?そして、多分あなたは私たちに伝えるべきですか?

実際には相関を計算する必要はないことに注意してください。ほとんどの場合、相関がしきい値よりも大きいかどうかを調べるだけで済みます。

corr = findCorrelation(extractedCharacter, storedCharacter)
..... more code to check if this is the best match ......

これにより、画像がどのように見えるかに応じて、最適化が行われる場合と行われない場合があります。

また、この私の質問のように、単純な低レベルの最適化により、ほぼ 4 倍の係数が得られることにも注意してください。多分あなたは本当にあなたが何をしているかを私たちに話すべきですか?

更新 1

ループ内の 3 つの積の計算により、命令レベルの並列処理が十分に行われるため、上記の質問のように手動でループを展開する必要はないと思います。

ただし、これら 3 つの積が何度か計算されることがわかりますが、 と の両方に100 * 15600依存するのはそのうちの 1 つだけです。だからあなたは計算することができますextractedCharacterstoredCharacter

100 + 15600 + 100 * 15600

の代わりに内積

 3 * 100 * 15600

このようにして、非常に簡単に 3 倍の係数を得ることができます。

か否か。このステップの後、関連するステップで計算された単一の合計があり、上記のリンクの問題が適用されます。また、その解決策 (手動で展開する) も同様です。

係数 5.2

結果

byte[]は非常にコンパクトですが、計算にはそれらを int に拡張する必要があり、ベンチマークが示すように時間がかかります。すべての相関が計算される前にbyte[]s をs に変換すると、時間を節約できます。int[]さらに良いのは、この変換をstoredCharacters事前に行うことができるという事実を利用することです。

手動でループを 2 回展開すると効果がありますが、それ以上展開しても効果はありません。

于 2014-05-14T14:40:30.690 に答える