machine-learning - 从不同布局的 PDF 文件中提取文本信息 - 机器学习

标签 machine-learning image-processing neural-network nlp computer-vision

我需要有关当前正在尝试创建的机器学习项目的帮助。

我收到了来自许多不同供应商的大量发票 - 全部都有自己独特的布局。我需要从发票中提取 3 个关键元素。这 3 元素均位于所有发票的表格/行项目中。

3 元素是:

  • 1:关税号(数字)
  • 2:数量(始终为数字)
  • 3:行总金额(货币值(value))

请参阅下面的屏幕截图,我在示例发票上标记了这些字段。

enter image description here

我使用基于正则表达式的模板方法开始了这个项目。然而,这根本无法扩展,我最终得到了大量不同的规则。

我希望机器学习可以在这里帮助我 - 或者也许是混合解决方案?

共同点

在我的所有发票中,尽管布局不同,每个行项目都始终包含一个关税号。此关税号码始终为 8 位数字,并且始终采用如下格式之一:

  • xxxxxxxx
  • xxxx.xxxx
  • xx.xx.xx.xx

(其中“x”是 0 - 9 之间的数字)。

此外,正如您在发票上看到的那样,每行都有单价和总金额。我需要的金额始终是每行的最高金额。

输出

对于像上面这样的每张发票,我需要每一行的输出。例如,这可能是这样的:

{
    "line":"0",
    "tariff":"85444290",
    "quantity":"3",
    "amount":"258.93"
},
{
    "line":"1",
    "tariff":"85444290",
    "quantity":"4",
    "amount":"548.32"
},
{
    "line":"2",
    "tariff":"76109090",
    "quantity":"5",
    "amount":"412.30"
}

从这里去哪里?

我不确定我想要做的事情属于机器学习,如果是,属于哪个类别。是计算机视觉吗?自然语言处理?命名实体识别?

我最初的想法是:

  1. 将发票转换为文本。 (发票都是可文本 PDF 格式,因此我可以使用 pdftotext 之类的工具来获取准确的文本值)
  2. 数量关税金额创建自定义命名实体
  3. 导出找到的实体。

但是,我觉得我可能错过了一些东西。

有人可以帮助我朝正确的方向前进吗?

编辑:

请参阅下面的更多示例,了解发票表部分的外观:

发票样本 #2 enter image description here

发票样本 #3 enter image description here

编辑2:

请参阅下面的三个示例图像,没有边框/边界框:

图片 1: Sample 1 without bbox

图 2: Sample 2 without bbox

图 3: Sample 3 without bbox

最佳答案

这是使用 OpenCV 的尝试,想法是:

  1. 获取二值图像。我们加载图像,使用放大 imutils.resize为了帮助获得更好的 OCR 结果(请参阅 Tesseract improve quality ),请转换为灰度,然后 Otsu's threshold获得二值图像(1 channel )。

  2. 删除表格网格线。我们创建 horizontal and vertical kernels然后执行morphological operations将相邻文本轮廓合并为单个轮廓。这个想法是将 ROI 行作为一个整体提取到 OCR。

  3. 提取行投资返回率。我们find contours然后使用 imutils.contours.sort_contours 从上到下排序。这确保我们以正确的顺序迭代每一行。从这里开始,我们迭代轮廓,使用 Numpy 切片提取行 ROI,使用 Pytesseract 进行 OCR。 ,然后解析数据。

<小时/>

这是每个步骤的可视化:

输入图片

enter image description here

二值图像

enter image description here

变形关闭

enter image description here

迭代每一行的可视化

enter image description here

提取的行 ROI

enter image description here enter image description here enter image description here

输出发票数据结果:

{'line': '0', 'tariff': '85444290', 'quantity': '3', 'amount': '258.93'}
{'line': '1', 'tariff': '85444290', 'quantity': '4', 'amount': '548.32'}
{'line': '2', 'tariff': '76109090', 'quantity': '5', 'amount': '412.30'}

不幸的是,在尝试第二张和第三张图像时,我得到的结果好坏参半。由于发票的布局都不同,因此此方法不会在其他图像上产生很好的结果。然而,这种方法表明,假设您有固定的发票布局,可以使用传统的图像处理技术来提取发票信息。

代码

import cv2
import numpy as np
import pytesseract
from imutils import contours
import imutils

pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"

# Load image, enlarge, convert to grayscale, Otsu's threshold
image = cv2.imread('1.png')
image = imutils.resize(image, width=1000)
height, width = image.shape[:2]
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Remove horizontal lines
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50,1))
detect_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(thresh, [c], -1, 0, -1)

# Remove vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,50))
detect_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(thresh, [c], -1, 0, -1)

# Morph close to combine adjacent contours into a single contour
invoice_data = []
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (85,5))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=3)

# Find contours, sort from top-to-bottom
# Iterate through contours, extract row ROI, OCR, and parse data
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
(cnts, _) = contours.sort_contours(cnts, method="top-to-bottom")

row = 0
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    ROI = image[y:y+h, 0:width]
    ROI = cv2.GaussianBlur(ROI, (3,3), 0)
    data = pytesseract.image_to_string(ROI, lang='eng', config='--psm 6')
    parsed = [word.lower() for word in data.split()] 
    if 'tariff' in parsed or 'number' in parsed:
        row_data = {}
        row_data['line'] = str(row)
        row_data['tariff'] = parsed[-1]
        row_data['quantity'] = parsed[2]
        row_data['amount'] = str(max(parsed[10], parsed[11]))
        row += 1

        print(row_data)
        invoice_data.append(row_data)
        
        # Visualize row extraction
        '''
        mask = np.zeros(image.shape, dtype=np.uint8)
        cv2.rectangle(mask, (0, y), (width, y + h), (255,255,255), -1)
        display_row = cv2.bitwise_and(image, mask)

        cv2.imshow('ROI', ROI)
        cv2.imshow('display_row', display_row)
        cv2.waitKey(1000)
        '''
print(invoice_data)
cv2.imshow('thresh', thresh)
cv2.imshow('close', close)
cv2.waitKey()

关于machine-learning - 从不同布局的 PDF 文件中提取文本信息 - 机器学习,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60074110/

相关文章:

matlab - 线性回归中的梯度下降出错

python-2.7 - 无法从朴素贝叶斯分类器生成 ROC-AUC 曲线

python - 具有 Maxpooling1D 和 channel_first 的 Keras 模型

image - OpenCV imwrite 给出了 jpeg 图像的褪色结果

ubuntu - 通过 cli 删除重复图像

python pytesseract.image_to_string 无法读取图像中的文本

python - 为什么我的 sklearn 自定义转换器在 ColumnTransformer 中使用时不保存属性?

machine-learning - Encog 神经网络 - 如何实际运行测试数据

python - Keras:使用 flow_from _directory() 函数为两个输入模型创建自定义生成器

neural-network - Dropout 可以提高训练数据性能吗?