【问题标题】:Coefficient Correlation Over a Large Binary Image Data-Set - Slow Performance大型二值图像数据集的系数相关性 - 性能缓慢
【发布时间】:2014-05-14 07:00:21
【问题描述】:

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

【问题讨论】:

  • 你的问题很模糊。无论如何,探索的方法不是先尝试与“原型”字母匹配,然后仅与与此类原型相关的字母进行比较。例如,如果一个字母与X 非常接近而与a 非常不同,那么您只需将其与xXY 进行比较,而不是与s 进行比较。当然,找到字母集及其最佳“原型”并非易事。
  • 你的字节数组有多大?您可以像 SJuan76 建议的那样为初步测试准备一个“低分辨率”模型(较小的阵列)
  • 你可以使用多个线程(我认为 i5 允许 4 个线程)。
  • 如果我理解正确的话,瓶颈是findCorrelation 调用的循环。如果您提供此方法的代码,可以提供更集中的提示和建议。否则,只能给出一般性陈述,例如“高级”优化(如前所述的多线程),或引用方法本身的提示(即是否可以通过某种散列或启发式算法进行优化) - 但是只要您不更详细地描述该方法,后者就很困难。
  • 您显示的 sn-p 是未优化的部分。 您隐藏的内容可能会有所改进(即findCorrelation)。在这个级别,您只能并行化(这可能是值得的,但加速受到内核数量的限制)。

标签: java performance ocr correlation coefficients


【解决方案1】:

如今,很难找到具有单核的 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

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

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

【讨论】:

  • 我在原始帖子中包含了 findCorrelation() 的代码。该过程返回两个图像 A 和 B 之间的相关系数,其中 A 和 B 是具有 0 和 1 值的相同大小的向量。返回的 corr 是一个介于 0.0 到 1.0 之间的值,表示两个图像的接近程度,1 表示它们是相同的
  • @javasuns:我明白了。这就是我在上面所说的dot product(我并不是说“相关性”是错误的,只是我的理解不同)。忘记上面提到的转换。我很快就会修改我的答案。
  • 嗯,我明白你在说什么,这可能会提高性能。我会发布我的更新结果
  • 好吧,我已经尝试将 byte 更改为 int,但我没有看到任何真正的性能差异。您使用什么版本的 Java?
  • 单独将bytes 更改为int 可能没有多大帮助;我猜你首先需要其他(更简单的)优化。 java -versionopenjdk version "1.9.0-internal",但这没关系(我已经运行了很多基准测试,当我暂时从 1.7 切换到这个实验设置时,它们几乎没有改变)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-17
  • 2019-10-18
  • 2020-03-04
  • 2020-04-16
  • 2013-04-20
  • 2018-12-14
相关资源
最近更新 更多