检测图像中的粗体(和斜体)文本

Detecting bold (and italic) text in an image

我想检测页面图像中的粗体(可能还有斜体)文本——想想 TIFF 或图像 PDF。我需要指向执行此操作的任何开源软件的指针。

这是一张说明此类文字的字典条目图片(来自 Tzeltal-西班牙语字典):

第一行是粗体,然后是斜体,然后是“普通”;第二个是粗体字,然后是普通字体。格式表示隐式结构:粗体表示词条,斜体表示词性,普通表示大多数其他内容。在不知道什么是粗体/斜体/正常的情况下,不可能将这些条目解析为结构化文本(如 XML)。

几年前,当我们的字典解析项目处于活跃状态时,我们使用 Tesseract 版本 3 对图像进行 OCR,并使用 hocr 输出为我们提供页面上的位置信息(例如,分离字典中的不同条目至关重要) ). hocr 输出还包括粗体标记 'strong' 和斜体标记 'em'。虽然 'em' 标记相当准确,但 'strong' 标记几乎是随机的。现在是 Tesseract 的第 4 版 doesn't even try (see also)。你仍然可以告诉 tesseract 使用旧引擎,但正如我所说,这似乎是完全不准确的,至少在我们提供给它的文本上是这样。

区分粗体文本和普通文本似乎并不难;我可以站在离我的显示器很远的地方,挑选出粗体和非粗体的部分,即使我无法在那个距离阅读文字。 (我想判断整个文本是粗体还是非粗体会更难,但当两者都出现时区分它们似乎很容易——对人类来说。)

我听说 ABBYY FineReader 输出有关字体样式的信息,但出于各种原因,这对我们的应用程序不起作用。

如果有一种非 OCR 方法来区分粗体文本和非粗体文本,将边界框放在粗体文本周围,我们可能可以将这些延伸与 Tesseract 输出的字符/单词的边界框相匹配(允许一些像素差异)。我知道有 research on this decades ago (also here),但有没有真正做到这一点的开源软件?

我发明了一些脚本:

KERNEL = np.asarray([
    [1, 1, 1, 1],
    [1, 1, 1, 1],
    [1, 1, 1, 1],
], np.uint8)
KERNEL_ITALIC = np.asarray([
    [0, 0, 1, 1],
    [0, 0, 1, 1],
    [0, 0, 1, 1],
    [0, 1, 1, 0],
    [0, 1, 1, 0],
    [0, 1, 1, 0],
    [1, 1, 0, 0],
    [1, 1, 0, 0],
    [1, 1, 0, 0],
], np.uint8)

def pre_process_italic(img):
    img_f = cv2.flip(img, 1)

    img = cv2.erode(img, KERNEL_ITALIC, iterations=1)
    img = cv2.dilate(img, KERNEL, iterations=1)

    img_f = cv2.erode(img_f, KERNEL_ITALIC, iterations=1)
    img_f = cv2.dilate(img_f, KERNEL, iterations=1)
    img_f = cv2.flip(img_f, 1)
    return img, img_f

def apply_func_italic(bbox, original, preprocessed):

    b_1 = bbox[1]
    b_3 = bbox[3]
    b_0 = bbox[0]
    b_2 = bbox[2]

    a, b = np.mean(original[b_1:b_3, b_0:b_2]), np.mean(preprocessed[b_1:b_3, b_0:b_2])

    return get_ratio(a, b)

def get_ratio(a, b):
    return ((a - b) / (a + b + 1e-8)) * 2

此 python 函数获取带有文本的图像并使一些 opencv 函数变形过程。之后函数 returns 两张图像:原始图像和处理过的图像,在此之后,您需要的是拥有单词的边界框并循环遍历它们并计算原始图像上 'ON' 像素与处理后像素的比率。有“get_ratio” - 它可以替换为另一个指标。我还没有找到更好的指标。