【问题标题】:Dictionary-based keyword detection基于字典的关键字检测
【发布时间】:2023-04-04 01:14:01
【问题描述】:

我想识别扫描文档中可能存在 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 选择?

【问题讨论】:

    标签: algorithm ocr levenshtein-distance error-correction


    【解决方案1】:

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

    我认为我们试图回答的问题是:

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

    想法 1

    OCR 文档包含带有一些“分数”的术语...

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

    • 订单分数 = sum(93,96,96,90,95)/5 = 94
    • 0rder with score = sum(90,96,96,90,95)/5 = 93
    • crder 得分 = sum(83,96,96,90,95)/5 = 92
    • erder 得分 = sum(82,96,96,90,95)/5 = 91
    • 得分 = sum(93,96,96,75,95)/5 = 91 的标准
    • 0rdar 分数 = sum(90,96,96,75,95)/5 = 90
    • crdar 分数 = sum(83,96,96,75,95)/5 = 89
    • erdar 分数 = sum(82,96,96,75,95)/5 = 88

    现在我们对每个候选者都有一个分数,我们可以得到一个文档的分数,给定一些查询(现在使用 levenshtein 距离...)

    给定关键字“订单”的文档得分是平均

    • (3-min(lev(order, order),3)*0.33) * 94,
    • (3-min(lev(0rder, order),3)*0.33) * 93,
    • (3-min(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)   |...
    

    其中 score(ord) = 'ord' 的三元概率

    例如,Google 图书给出了任何三元组的三元组概率(参见: http://books.google.com/ngrams/chart?content=ord&corpus=0&smoothing=3&year_start=1970&year_end=2000)

    我们还可以计算一元、二元、四元...;然后我们可以根据单词本身的“unigram”概率来计算分数;单词的二元组等等……;那么我们也可以应用一些纯粹的分析语言模型

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

    想法 3

    好的,以上导致术语/分数的爆炸式增长......这是计算密集型的;所以我们使用一些魔法根据想法 1 和 2 为每个术语构建概率 DFA。该文档现在包含概率 DFA 而不是术语。 Lucene 的人已经做了一些工作来构建 Levenshtein DFA 并允许检查 DFA1 和 DFA2 是否快速匹配......

    【讨论】:

      【解决方案2】:

      首先,我认为你的程序给你的是 P(observation|symbol),而不是 P(symbol|observation)。 P(symbol|observation) \proportional P(observation|symbol)*P(symbol) .

      例如,对于支付中的那个e,虽然观察到欧元的模式给出符号的概率最高,但观察到欧元的概率非常小。因此,它很可能是“e”,而不是欧元。

      因此,我的建议是对所有可能的单词求和 log( P(observation|symbol)*P(symbol) ),然后选择使该值最大化的单词。

      此外,您可以通过使用上下文来使用更准确的估计,而不是使用 P(symbol)。

      【讨论】:

      • 好主意,但这不是使用“关键字”本身;本质上,您的建议似乎是将 unigram 概率与 ocr 概率结合起来。
      猜你喜欢
      • 2019-02-23
      • 1970-01-01
      • 2021-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-16
      • 1970-01-01
      相关资源
      最近更新 更多