受Borislav的回答启发,我刚刚写了一些Python代码,也适用于手写文字识别。虽然有点混乱,但我认为你可以了解如何实现这个功能。
一个类来保存每个单词的一些扩展数据,例如单词的平均y位置,我用它来计算单词之间的差异:
import re
from operator import attrgetter
import numpy as np
class ExtendedAnnotation:
def __init__(self, annotation):
self.vertex = annotation.bounding_poly.vertices
self.text = annotation.description
self.avg_y = (self.vertex[0].y + self.vertex[1].y + self.vertex[2].y + self.vertex[3].y) / 4
self.height = ((self.vertex[3].y - self.vertex[1].y) + (self.vertex[2].y - self.vertex[0].y)) / 2
self.start_x = (self.vertex[0].x + self.vertex[3].x) / 2
def __repr__(self):
return '{' + self.text + ', ' + str(self.avg_y) + ', ' + str(self.height) + ', ' + str(self.start_x) + '}'
使用该数据创建对象:
def get_extended_annotations(response):
extended_annotations = []
for annotation in response.text_annotations:
extended_annotations.append(ExtendedAnnotation(annotation))
del extended_annotations[0]
return extended_annotations
计算阈值。
首先,将所有单词按其y位置排序,即定义为所有4个角的平均值。此时x位置不相关。
然后,计算每个单词和其后续单词之间的差异。对于一条完全直线的单词,您期望每两个单词之间的y位置差异为0。即使是手写体,也应该在1~10左右。
但是,每当有换行时,前一行的最后一个单词与新一行的第一个单词之间的差异要比那大得多,例如50或60。
因此,为了决定是否应在两个单词之间换行,使用差异的标准偏差。
def get_threshold_for_y_difference(annotations):
annotations.sort(key=attrgetter('avg_y'))
differences = []
for i in range(0, len(annotations)):
if i == 0:
continue
differences.append(abs(annotations[i].avg_y - annotations[i - 1].avg_y))
return np.std(differences)
计算出阈值后,将所有单词的列表按照相应的行进行分组。
def group_annotations(annotations, threshold):
annotations.sort(key=attrgetter('avg_y'))
line_index = 0
text = [[]]
for i in range(0, len(annotations)):
if i == 0:
text[line_index].append(annotations[i])
continue
y_difference = abs(annotations[i].avg_y - annotations[i - 1].avg_y)
if y_difference > threshold:
line_index = line_index + 1
text.append([])
text[line_index].append(annotations[i])
return text
最后,每一行都按照它们的x位置进行排序,以便从左到右将它们放入正确的顺序中。
然后使用一些正则表达式来删除标点符号前面的空格。
def sort_and_combine_grouped_annotations(annotation_lists):
grouped_list = []
for annotation_group in annotation_lists:
annotation_group.sort(key=attrgetter('start_x'))
texts = (o.text for o in annotation_group)
texts = ' '.join(texts)
texts = re.sub(r'\s([-;:?.!](?:\s|$))', r'\1', texts)
grouped_list.append(texts)
return grouped_list