大型二值图像数据集的系数相关性 - 慢性能

时间:2014-05-14 07:00:21

标签: java performance ocr correlation coefficients

我正在尝试通过计算从图像中提取的字符与我预先存储在数据库中的每个字符之间的系数相关性来构建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;
}

1 个答案:

答案 0 :(得分:0)

如今,很难找到具有单核的CPU(即使在移动设备中)。由于任务很好地分开,你只能用几行来完成。所以我会去做,虽然收益是有限的。

如果你的意思是cross-correlation,那么像DFTDCT之类的转换可能有所帮助。他们肯定会为大图片做,但是对于你的12x16,我不确定。

也许你的意思是dot product?也许你应该告诉我们?

请注意,您实际上不需要计算相关性,大多数情况下您只需要查明它是否大于阈值:

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

这可能会导致一些优化,具体取决于图像的外观。

另请注意,简单的低级优化可以为您提供近4倍的question of mine。也许你真的应该告诉我们你在做什么?

更新1

我想由于在循环中计算了三个产品,因此有足够的指令级并行性,因此不需要像my above question那样展开手动循环。

但是,我发现这三种产品的计算时间为100 * 15600次,而其中只有一种产品依赖于extractedCharacterstoredCharacter。所以你可以计算

100 + 15600 + 100 * 15600

点积而不是

 3 * 100 * 15600

这样你很容易得到三分之一。

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

因子5.2

results

虽然byte[]非常紧凑,但计算涉及将它们扩展为整数,这需要花费一些时间,因为benchmark显示。在计算所有相关性之前将byte[]转换为int[]可以节省时间。更好的方法是利用事先storedCharacters的转换可以事先完成。

手动循环展开两次有帮助,但展开更多没有。