基于字典的关键字检测

时间:2012-05-02 15:44:10

标签: algorithm ocr levenshtein-distance error-correction

我想识别扫描文档中可能存在OCR错误的关键字。根据每个字符及其扫描文档替代品的关键字和置信度值列表,如何开发可靠识别关键字的算法?

对于OCR,我使用的是Tesseract,它为每个角色及其最佳替代品提供置信度值。所以对于每个单词我都有这样的列表:

 Word=order
 [0] o (93%) [alts: 0 (90%), c (83%), e (82%)]
 [1] r (96%)
 [2] d (96%)
 [3] e (90%) [alts: a (75%)]
 [4] r (95%) 

另一个例子,包括OCR错误:

 Word=PaYmeHI (Payment would be correct)
 [0] P (81%) [alts: p (78%), D (68%)]
 [1] a (76%) [alts: 3 (73%), e (63%), ö (61%)]
 [2] Y (87%) [alts: V (86%)]
 [3] m (83%) 
 [4] E (71%) [alts: € (79%), 9 (72%), % (67%), e (65%), B (64%), G (64%)]
 [5] H (76%) [alts: n (83%), D (74%), N (70%), ü (69%)]
 [6] I (75%) [alts: t (69%), { (67%), 1 (65%), i (61%)]

正如您所看到的,tesseract并不总是选择具有最高百分比的结果(4,5)。

从略读结果看,大多数字符值大于90%是正确的。但是,不良结果不一定包含备选列表中的正确字符(参见[2],它应该是小写y

目前,我正在使用Levenshtein距离和字符串长度获得候选人列表。此外,我排除了lev2 > 3的关键字。这只是硬编码,因为我仍然在寻找确定阈值的好方法。

      int lev = getLevenshteinDistance(keyword, s);
      int lev2 = getLevenshteinDistance(keyword.toLower(), s.toLower());
      int len = Math.abs(keyword.length - s.length); 
      int x = lev + lev2 + len;

我按x排序关键字列表,以获得最可能的结果。

首先,我正在寻找一种基于OCR结果和字符串长度来确定良好阈值的方法。短字符串将需要比较大字符串更低的阈值和固定的OCR结果。以上面的示例为例:对于单词顺序lev2 <= 1,就足够了,而对于payment,至少应计算lev2 <= 3

其次,我如何判断其中一位候选人是否与该单词匹配?在lev == 0的情况下以及当所有字符的置信度值为>= 90时,这是显而易见的。但考虑到糟糕的OCR结果,我可以开发哪种算法还包括其他OCR选择?

2 个答案:

答案 0 :(得分:2)

我一直在考虑为我的一个项目做类似的事情;我还没有得到任何好的答案,但这里有一些想法:

我认为我们要回答的问题是:

此文件(OCR结果)是否包含“订单”一词?

创意1

OCR文件包含一些带有“得分”的条款......

因此,在您的示例中,该文档包含:

  • 订单得分=总和(93,96,96,90,95)/ 5 = 94
  • 0rder,得分=总和(90,96,96,90,95)/ 5 = 93
  • crder,得分=总和(83,96,96,90,95)/ 5 = 92
  • 错误得分=总和(82,96,96,90,95)/ 5 = 91
  • ordar,得分=总和(93,96,96,75,95)/ 5 = 91
  • 0rdar,得分=总和(90,96,96,75,95)/ 5 = 90
  • crdar,得分=总和(83,96,96,75,95)/ 5 = 89
  • erdar,得分=总和(82,96,96,75,95)/ 5 = 88

现在我们有一个每个候选人的分数,我们可以得到一个文件的分数,给出一些查询(现在使用levenshtein距离...)

给予关键字“订单”的doc得分是

的平均值
  • (3分钟(lev(顺序,顺序),3)* 0.33)* 94,
  • (3分钟(lev(0rder,order),3)* 0.33)* 93,
  • (3分钟(lev(crder,order),3)* 0.33)* 92,
  • ...,
  • ...

如果此分数高于某个阈值,则该文档被视为与“订单”匹配

创意2

我们可以使用某些语言模型来改善OCR结果

每个学期的计算分数如下:

term        | ocr_score   |ngram score            |combined score
------------+-------------+-----------------------+---------------
order   | 94          |score(ord, rde, der)   |ocr*ngram
0rder   | 93          |score(0rd, rde, der)   |ocr*ngram
crder   | 92          |score(crd, rde, der)   |ocr*ngram
erder   | 91          |score(erd, rde, der)   |...
ordar   | 91          |score(ord, rda, der)   |...
0rdar   | 90          |score(0rd, rda, der)   |...
crdar   | 89          |score(crd, rda, der)   |...
erdar   | 88          |score(erd, rda, der)   |...

得分(ord)='ord'的三元组概率

例如,Google Books为任何三元组提供了三元组概率(参见: http://books.google.com/ngrams/chart?content=ord&corpus=0&smoothing=3&year_start=1970&year_end=2000

我们还可以计算unigram,bigram,quadgrams ......;然后我们可以根据单词本身的“unigram”概率来计算得分;言语之重等......那么我们也可以应用一些纯粹的分析语言模型

所以我们现在每个“候选词汇”都有更多的分数,我们将它们与每个分数的一些权重相结合,以获得该术语的综合分数

创意3

好的,所以上面会导致术语/分数的爆炸......这是计算密集型的;所以我们使用一些魔法为每个术语建立一个概率DFA,基于思路1和1。该文件现在包含概率DFA而不是术语。 Lucene的家伙已经做了一些工作来建立Levenshtein DFA并允许检查DFA1和DFA2是否快速匹配......

答案 1 :(得分:1)

首先,我认为你的程序给你P(观察符号),而不是P(符号|观察)。 P(符号)\比例P(观察符号)* P(符号)。

例如,对于支付中的e,尽管观察到的模式给出符号的概率对于欧元来说是最高的,但观察欧元的概率非常小。因此,它很可能是'e',而不是欧元。

因此,我的建议是对所有可能的单词求和(P(观察|符号)* P(符号))并选择最大化该值的那个。

此外,您可以使用上下文来使用P(符号),而不是使用P(符号)。