我想识别扫描文档中可能存在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选择?
答案 0 :(得分:2)
我一直在考虑为我的一个项目做类似的事情;我还没有得到任何好的答案,但这里有一些想法:
我认为我们要回答的问题是:
此文件(OCR结果)是否包含“订单”一词?
创意1
OCR文件包含一些带有“得分”的条款......
因此,在您的示例中,该文档包含:
现在我们有一个每个候选人的分数,我们可以得到一个文件的分数,给出一些查询(现在使用levenshtein距离...)
给予关键字“订单”的doc得分是
的平均值如果此分数高于某个阈值,则该文档被视为与“订单”匹配
创意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(符号)。