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 个存储的二进制字符。检查每个提取的字符和每个存储的字符之间的系数相关性会对性能产生影响,因为它需要大约 15-20 秒才能完成每个图像,使用 Intel i5 CPU。有没有办法提高这个程序的速度,或者提出另一种构建这个程序的方法,带来类似的结果。(通过将每个字符与如此大的数据集进行比较产生的结果非常好)。

先感谢您

更新 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

我想由于循环中三个乘积的计算,有足够的指令级并行性,因此不需要像我上面的问题中那样手动展开循环。

但是,我看到这三个产品100 * 15600有时会被计算,而其中只有一个依赖于extractedCharacterstoredCharacter。所以你可以计算

100 + 15600 + 100 * 15600

点积而不是

 3 * 100 * 15600

这样,您可以很容易地获得三倍。

或不。在此步骤之后,在相关步骤中计算了一个总和,并且上面链接的问题适用。它的解决方案也是如此(手动展开)。

因素 5.2

结果

虽然byte[]非常紧凑,但计算涉及将它们扩展到整数,正如我的基准测试所示,这需要一些时间。在计算所有相关性之前将 s转换为byte[]s可以节省时间。int[]更好的是利用storedCharacters可以预先完成这种转换的事实。

手动循环展开两次有帮助,但展开更多则无济于事。

于 2014-05-14T14:40:30.690 回答