文本对比算法的简单实现
我们小组当前有需要要测试ocr场景文字识别的效果,给定真实文本和ocr模型预测的文本,希望给出评价指标验证模型的效果。
去网上查阅了python有一个特别好用的文本对比工具包,difflib,做了一些调研之后,依旧选择自己写代码实现文本的对比函数。difflib初步感觉不好用的原因是,如果两行文本的文字不一样的稍微多一点,就无法给表示出其中的差异了。比如
假设真实语句为:
正式始工作。好好学习
检测出来的语句为:
正式开始工作
这两句话,我希望可以得到检测到的比真实的多了一个字,少了四个汉字的情况。而使用difflib的compare方法,只会认为这两句话完全不一样。
另一个相似的情况是
假设真实语句为:
正式始工作。好好学习
检测出来的语句为:
正式开始工作
这时,difflib就可以检测出这两句话的区别,并给予标注
文本对比函数主要为了测试ocr文本检测的效果,因此我采取一行为最小的检测单元,分别输入text1标准结果、text2录入结果,检测每一行文本检测的匹配字符数、错字字符数、多字字符数、漏字字符数。
代码的主要思路参考文本比对的一种算法探索、比对算法中的难点及解决方法
其主要的思想是:p1,p2分别指向两个句子的指针。
-
当两句话的指针位置
text1[p1]==text[p2]
时,两个指针同时指向下一个位置。 -
当指针的位置的内容不同的时候,保持p2不变,首先遍历text1的p1指针后面的位置,一直遍历到最后,如果出现了
text1[p1']==text[p2]
,那么意味着检测的语句有漏检的字符。考虑下面的例子 **正式开始工作。** **正式工作。**
-
如果p1'遍历到text1的末尾依旧没有找到,则进行多字检测。也就是保持p1不变,遍历text2在p2后面的位置,看看是否有
text1[p1]==text[p2']
的情况,如果有,则意味着检测语句多出了真实语句没有的词语。考虑下面的例子 **正式工作。** **正式开始工作。**
-
如果这两种遍历方式都没有找到结果,那么意味着存在错字问题,将p1和p2同时+1.
代码如下:
def get_textline_match(text1, text2):
lose_words = 0
more_words = 0
wrong_words = 0
match_words = 0
p1 = 0
t1 = 0
p2 = 0
t2 = 0
len1 = len(text1)
len2 = len(text2)
def loss_words(p, text, word):
len1 = len(text)
if p >= len1:
return -1
while p < len1:
if text[p] == word:
return p
else:
p += 1
return -1
while (p1 < len1) & (p2 < len2):
if text1[p1] == text2[p2]:
match_words += 1
p1 += 1
p2 += 1
else:
t1 = loss_words(p1 + 1, text1, text2[p2])
if t1 == -1: # 搜索标准行,没有找到
t2 = loss_words(p2 + 1, text2, text1[p1])
if t2 == -1: # 搜素识别行,没有找到对应位置,表示这是一个错字
wrong_words += 1
p1 += 1
p2 += 1
else:
more_words += (t2 - p2)
p2 = t2
else:
lose_words += (t1 - p1)
p1 = t1
lose_words += len1 - p1
more_words += len2 - p2
return match_words, wrong_words, lose_words, more_words
if __name__ == "__main__":
text1 = """我们班里喜欢数学的学生大多数是女生。"""
text2 = """我们班里的学生大多数是女生。"""
match_words, wrong_words, lose_words, more_words = get_textline_match(text1, text2)
print("匹配字符数量: ", match_words)
print("错误字符数量: ", wrong_words)
print("丢失字符数量: ", lose_words)
print("多出字符数量: ", more_words)
会输出结果
匹配字符数量: 14
错误字符数量: 0
丢失字符数量: 4
多出字符数量: 0
需要的优化是,为了加快速度,可以不必一直遍历到末尾,只要遍历到四五个字之后,如果还没有出现,就可以认为是漏字、多字或者错字了。
如果有更好的思路或者这边代码存在某些我还没有发现的问题,欢迎留言讨论