引入文档图像的多模态文本-图像增强
在这篇博文中,我们将提供一个关于如何使用与 Albumentations AI 协作开发的新文档图像数据增强技术的教程。
动机
视觉语言模型(VLM)具有广泛的应用范围,但通常需要针对特定用例进行微调,尤其是对于包含文档图像(即具有大量文本内容的图像)的数据集。在这种情况下,文本和图像在模型训练的所有阶段进行交互至关重要,而对两种模态应用增强确保了这种交互。本质上,我们希望模型学会正确阅读,这在数据缺失的常见情况下极具挑战性。
因此,在解决有限数据集模型微调的挑战时,有效的文档图像数据增强技术的需求变得显而易见。一个普遍的担忧是,常见的图像变换,如调整大小、模糊或更改背景颜色,可能会对文本提取精度产生负面影响。
我们认识到需要数据增强技术来在增强数据集的同时保持文本的完整性。这种数据增强可以促进新文档的生成或现有文档的修改,同时保持其文本质量。
介绍
为了解决这个需求,我们引入了与 Albumentations AI 协作开发的新数据增强流水线。该流水线同时处理图像及其中的文本,为文档图像提供了全面的解决方案。这类数据增强是多模态的,因为它同时修改图像内容和文本注释。
正如之前一篇博客文章所讨论的,我们的目标是验证在 VLM 预训练期间整合文本和图像增强的有效性。详细参数和用例示例可以在Albumentations AI 文档中找到。Albumentations AI 使得动态设计这些增强并将其与其他类型的增强集成成为可能。
方法
为了增强文档图像,我们首先随机选择文档中的行。超参数 `fraction_range` 控制要修改的边界框分数。
接下来,我们对相应的文本行应用几种文本增强方法之一,这些方法常用于文本生成任务。这些方法包括随机插入、删除和交换,以及停用词替换。
修改文本后,我们用黑色涂抹图像中插入文本的部分并进行修补,使用原始边界框大小作为新文本字体大小的代理。字体大小可以用参数 `font_size_fraction_range` 指定,它决定了选择字体大小作为边界框高度分数范围。请注意,修改后的文本和相应的边界框可以被检索并用于训练。这个过程产生了一个语义相似文本内容和视觉扭曲图像的数据集。
文本图像增强的主要功能
该库主要用于两个目的:
在图像上插入任意文本:此功能允许您在文档图像上叠加文本,有效地生成合成数据。通过使用任意随机图像作为背景并渲染全新的文本,您可以创建多样化的训练样本。OCR-free 文档理解转换器中引入了类似的技术,称为 SynthDOG。
在图像上插入增强文本:这包括以下文本增强:
- 随机删除:随机从文本中删除单词。
- 随机交换:交换文本中的单词。
- 停用词插入:将常用停用词插入文本中。
将这些增强与 Albumentations 的其他图像变换结合,可以同时修改图像和文本。您也可以检索增强后的文本。
注意:此仓库中介绍的数据增强流水线的初始版本包含同义词替换。此版本中已将其删除,因为它会导致显著的时间开销。
安装
!pip install -U pillow
!pip install albumentations
!pip install nltk
import albumentations as A
import cv2
from matplotlib import pyplot as plt
import json
import nltk
nltk.download('stopwords')
from nltk.corpus import stopwords
可视化
def visualize(image):
plt.figure(figsize=(20, 15))
plt.axis('off')
plt.imshow(image)
加载数据
请注意,对于这种类型的增强,您可以使用 IDL 和 PDFA 数据集。它们提供了您想要修改的行的边界框。对于本教程,我们将重点关注 IDL 数据集中的样本。
bgr_image = cv2.imread("examples/original/fkhy0236.tif")
image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)
with open("examples/original/fkhy0236.json") as f:
labels = json.load(f)
font_path = "/usr/share/fonts/truetype/liberation/LiberationSerif-Regular.ttf"
visualize(image)
我们需要正确预处理数据,因为边界框的输入格式是标准化的 Pascal VOC。因此,我们构建元数据如下:
page = labels['pages'][0]
def prepare_metadata(page: dict, image_height: int, image_width: int) -> list:
metadata = []
for text, box in zip(page['text'], page['bbox']):
left, top, width_norm, height_norm = box
metadata.append({
"bbox": [left, top, left + width_norm, top + height_norm],
"text": text
})
return metadata
image_height, image_width = image.shape[:2]
metadata = prepare_metadata(page, image_height, image_width)
随机交换
transform = A.Compose([A.TextImage(font_path=font_path, p=1, augmentations=["swap"], clear_bg=True, font_color = 'red', fraction_range = (0.5,0.8), font_size_fraction_range=(0.8, 0.9))])
transformed = transform(image=image, textimage_metadata=metadata)
visualize(transformed["image"])
随机删除
transform = A.Compose([A.TextImage(font_path=font_path, p=1, augmentations=["deletion"], clear_bg=True, font_color = 'red', fraction_range = (0.5,0.8), font_size_fraction_range=(0.8, 0.9))])
transformed = transform(image=image, textimage_metadata=metadata)
visualize(transformed['image'])
随机插入
在随机插入中,我们向文本中插入随机单词或短语。在这种情况下,我们使用停用词,这些词是语言中常见的词,在自然语言处理(NLP)任务中经常被忽略或过滤掉,因为它们与其他词相比携带的意义信息较少。停用词的例子包括“is”、“the”、“in”、“and”、“of”等。
stops = stopwords.words('english')
transform = A.Compose([A.TextImage(font_path=font_path, p=1, augmentations=["insertion"], stopwords = stops, clear_bg=True, font_color = 'red', fraction_range = (0.5,0.8), font_size_fraction_range=(0.8, 0.9))])
transformed = transform(image=image, textimage_metadata=metadata)
visualize(transformed['image'])
我们可以与其他变换结合吗?
让我们使用 A.Compose
定义一个复杂的变换流水线,其中包括指定字体属性和停用词的文本插入、普朗克抖动和仿射变换。首先,我们使用 A.TextImage
将文本插入图像,并使用指定的字体属性,清晰的背景和红色字体颜色。还指定了要插入文本的分数和大小。然后使用 A.PlanckianJitter
改变图像的颜色平衡。最后,使用 A.Affine
应用仿射变换,其中可以包括缩放、旋转和翻译图像。
transform_complex = A.Compose([A.TextImage(font_path=font_path, p=1, augmentations=["insertion"], stopwords = stops, clear_bg=True, font_color = 'red', fraction_range = (0.5,0.8), font_size_fraction_range=(0.8, 0.9)),
A.PlanckianJitter(p=1),
A.Affine(p=1)
])
transformed = transform_complex(image=image, textimage_metadata=metadata)
visualize(transformed["image"])
如何获取更改后的文本?
要提取文本更改所在的边界框索引信息以及相应的转换文本数据,请运行以下单元格。这些数据可以有效地用于训练模型识别和处理图像中的文本更改。
transformed['overlay_data']
[{'bbox_coords': (375, 1149, 2174, 1196),
'text': "Lionberger, Ph.D., (Title: if Introduction to won i FDA's yourselves Draft Guidance once of the wasn't General Principles",
'original_text': "Lionberger, Ph.D., (Title: Introduction to FDA's Draft Guidance of the General Principles",
'bbox_index': 12,
'font_color': 'red'},
{'bbox_coords': (373, 1677, 2174, 1724),
'text': "After off needn't were a brief break, ADC member mustn Jeffrey that Dayno, MD, Chief Medical Officer for at their Egalet",
'original_text': 'After a brief break, ADC member Jeffrey Dayno, MD, Chief Medical Officer at Egalet',
'bbox_index': 19,
'font_color': 'red'},
{'bbox_coords': (525, 2109, 2172, 2156),
'text': 'll Brands recognize the has importance and of a generics ADF guidance to ensure which after',
'original_text': 'Brands recognize the importance of a generics ADF guidance to ensure',
'bbox_index': 23,
'font_color': 'red'}]
合成数据生成
这种增强方法可以扩展到合成数据的生成,因为它能够在任何背景或模板上渲染文本。
template = cv2.imread('template.png')
image_template = cv2.cvtColor(template, cv2.COLOR_BGR2RGB)
transform = A.Compose([A.TextImage(font_path=font_path, p=1, clear_bg=True, font_color = 'red', font_size_fraction_range=(0.5, 0.7))])
metadata = [{
"bbox": [0.1, 0.4, 0.5, 0.48],
"text": "Some smart text goes here.",
}, {
"bbox": [0.1, 0.5, 0.5, 0.58],
"text": "Hope you find it helpful.",
}]
transformed = transform(image=image_template, textimage_metadata=metadata)
visualize(transformed['image'])
结论
与 Albumentations AI 合作,我们引入了文本图像增强,这是一种修改文档图像及其文本的多模态技术。通过结合随机插入、删除、交换和停用词替换等文本增强与图像修改,该流水线可以生成多样化的训练样本。
有关详细参数和用例说明,请参阅Albumentations AI 文档。我们希望这些增强能对您改进文档图像处理工作流程有所帮助。
参考
@inproceedings{kim2022ocr,
title={Ocr-free document understanding transformer},
author={Kim, Geewook and Hong, Teakgyu and Yim, Moonbin and Nam, JeongYeon and Park, Jinyoung and Yim, Jinyeong and Hwang, Wonseok and Yun, Sangdoo and Han, Dongyoon and Park, Seunghyun},
booktitle={European Conference on Computer Vision},
pages={498--517},
year={2022},
organization={Springer}
}