受 Borislav 的回答启发,我刚刚为 python 写了一些也适用于手写的东西。这很混乱,而且我是 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))
# delete last item, as it is the whole text I guess.
del extended_annotations[0]
return extended_annotations
计算阈值。
首先,所有单词 a 按它们的 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