如何以表格格式从发票中提取数据
Posted
技术标签:
【中文标题】如何以表格格式从发票中提取数据【英文标题】:How to extract data from invoices in tabular format 【发布时间】:2020-07-30 14:28:24 【问题描述】:我正在尝试使用计算机视觉从 pdf/图像发票中提取数据。为此,我使用了基于 ocr 的 pytesseract。 这是样本发票 您可以在下面找到相同的代码
import pytesseract
img = Image.open("invoice-sample.jpg")
text = pytesseract.image_to_string(img)
print(text)
通过使用 pytesseract 我得到了以下输出
http://mrsinvoice.com
’ Invoice
Your Company LLC Address 123, State, My Country P 111-222-333, F 111-222-334
BILLTO:
fofin Oe Invoice # 00001
Alpha Bravo Road 33 Invoice Date 32/12/2001
P: 111-292-333, F: 111-222-334
client@example.net Nomecof Reps Bob
Contact Phone 101-102-103
SHIPPING TO:
eine ce Payment Terms ash on Delivery
Office Road 38
P: 111-333-222, F: 122-222-334 Amount Due: $4,170
office@example.net
NO PRODUCTS / SERVICE QUANTITY / RATE / UNIT AMOUNT
HOURS: PRICE
1 tye 2 $20 $40
2__| Steering Wheel 5 $10 $50
3 | Engine oil 10 $15 $150
4 | Brake Pad 24 $1000 $2,400
Subtotal $275
Tax (10%) $27.5
Grand Total $202.5
‘THANK YOU FOR YOUR BUSINESS
但问题是我想提取文本并将其分成不同的部分,如供应商名称、发票编号、项目名称和项目数量。 预期输出
'date': (2014, 6, 4), 'invoice_number': 'EUVINS1-OF5-DE-120725895', 'amount': 35.24, 'desc': 'Invoice EUVINS1-OF5-DE-120725895 from Amazon EU'
我也尝试过invoice2data
python 库,但它也有很多限制。我还尝试了正则表达式和opencv的canny边缘检测来分别检测文本框,但未能达到预期的结果
你们能帮帮我吗
【问题讨论】:
图片格式是标准吗?表格、名称等是否会出现在与所附示例相同的位置? 不,没有标准格式,因为不同的产品卖家有不同的发票格式。但如果你说的是可能的,那么它也可以。 我认为您应该使用 Google Vision API 而不是tesseract
,它将返回各个段落的边界框以及 OCR 文本,然后您可以构建一些正则表达式类型的东西来检测地址块或名称块或表格数据等。
如果没有格式,正则表达式会有什么用?使用正则表达式不是硬编码吗?你能推荐一些与机器学习相关的东西吗?
@MayurSatav - 遇到与您相同的问题,因此您是否收到任何解决方案,请建议已检查但未获得相关解决方案。
【参考方案1】:
您必须进行更多处理,尤其是因为 BILL TO 和 SHIPPING TO 未与发票表对齐。但是您可以使用以下代码作为基础。
import cv2
import pytesseract
from pytesseract import Output
import pandas as pd
img = cv2.imread("aF0Dc.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
custom_config = r'-l eng --oem 1 --psm 6 '
d = pytesseract.image_to_data(thresh, config=custom_config, output_type=Output.DICT)
df = pd.DataFrame(d)
df1 = df[(df.conf != '-1') & (df.text != ' ') & (df.text != '')]
pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)
sorted_blocks = df1.groupby('block_num').first().sort_values('top').index.tolist()
for block in sorted_blocks:
curr = df1[df1['block_num'] == block]
sel = curr[curr.text.str.len() > 3]
# sel = curr
char_w = (sel.width / sel.text.str.len()).mean()
prev_par, prev_line, prev_left = 0, 0, 0
text = ''
for ix, ln in curr.iterrows():
# add new line when necessary
if prev_par != ln['par_num']:
text += '\n'
prev_par = ln['par_num']
prev_line = ln['line_num']
prev_left = 0
elif prev_line != ln['line_num']:
text += '\n'
prev_line = ln['line_num']
prev_left = 0
added = 0 # num of spaces that should be added
if ln['left'] / char_w > prev_left + 1:
added = int((ln['left']) / char_w) - prev_left
text += ' ' * added
text += ln['text'] + ' '
prev_left += len(ln['text']) + added + 1
text += '\n'
print(text)
结果
bhttps//mrsinvoice.com
Lp
I |
Your Company LLC Address 123, State, My Country P 111-222-333, F 111-222-334
BILL TO:
P: 111-222-333, F: 111-222-334 m .
dlent@ccomplent
Contact Phone 101-102-103
john Doe office ayment Terms ash on Delivery
Office Road 38
P: 111-833-222, F: 122-222-334 Amount Due: $4,170
office@example.net
NO PRODUCTS / SERVICE QUANTITY / RATE / UNIT AMOUNT
HOURS, PRICE
1 | tyre 2 $20 $40
2 | Steering Wheet 5 $10 $50
3 | Engine ol 40 $15 $150
4 | Brake Pad 2a $1000 $2,400
Subtotal $275
Tax (10%) $275
Grand Total $302.5
‘THANK YOU FOR YOUR BUSINESS
【讨论】:
以上是关于如何以表格格式从发票中提取数据的主要内容,如果未能解决你的问题,请参考以下文章