澄迈县网站建设_网站建设公司_后端开发_seo优化
2025/12/24 19:27:28 网站建设 项目流程

原文:towardsdatascience.com/how-to-effortlessly-extract-receipt-information-with-ocr-and-gpt-4o-mini-0825b4ac1fea

在这篇文章中,我将向您展示如何从收据中提取信息,给出一个简单的收据示例。首先,我们将利用 OCR 从收据中提取信息。然后,这些信息将被发送到 GPT-4o mini 模型进行信息提取。我的这个项目的目标是开发一个应用程序,只需拍摄收据的照片并选择哪些项目属于哪个人,就可以简单地分割账单。这篇文章将专注于实现这一目标的信息提取部分。

![从收据中提取信息使用 OCR 和 GPT-4o mini。图片由 ChatGPT 提供。OpenAI。(2024)ChatGPT(4o)[大型语言模型]。chatgpt.com/c/c567fd8c-1955-4af9-8566-0a9393e970e5]

使用 OCR 和 GPT-4o mini 从收据中提取信息。图片由 ChatGPT 提供。OpenAI。(2024)ChatGPT(4o)[大型语言模型]。chatgpt.com/c/c567fd8c-1955-4af9-8566-0a9393e970e5

本文开发的应用程序可在Google Play上访问。

动机

在处理收据并计算每个人的份额时,例如在参观餐厅后,这会变得很麻烦。我遇到过这个问题很多次,因此想要找到一个更有效的解决方案。因此,我想到了BillSplitter应用程序。其想法是用户可以拍摄收据的照片,应用程序将利用 OCR 和语言模型来处理收据并提取每一项及其对应的价格,用户可以简单地选择哪个人应该支付哪一项。最终,用户会收到一个概述,显示每个人应支付多少。

目录

· 动机 · 目录 · 从收据中提取文本 · 使用 GPT-4o mini 进行信息提取 · 审查结果 ∘ 第一张收据 ∘ 第二张收据 ∘ 第三张收据 · 结论

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/003e7b3d41080e45c16904107afdb9d3.png

本文使用的流程图。您从收据的图片开始,从中提取文本。然后您将使用 GPT-4o mini 来使用 OCR 输出提取收据上每个项目和相应的价格。图片由作者提供。

从收据中提取文本

首先,可以使用 OCR 引擎从收据中提取文本。有无数开源的 OCR 引擎,但本项目将利用 EasyOCR 因为它的有效性和易用性。

首先,您必须导入所需的包:

importeasyocrimportcv2importmatplotlib.pyplotaspltimportrequestsimporttorchimportpytesseractfromPILimportImageimportjsonimportnumpyasnp

您可以使用 pip 安装它。请注意,为了在 GPU 上运行 EasyOCR(强烈推荐,因为它可以节省大量时间),我必须明确使用 GPU 安装 PyTorch:

pip3 install torch torchvision torchaudio--index-url https://download.pytorch.org/whl/cu118

我在 Windows 和 CUDA 11.8 上使用了这个方法,但如果您使用其他操作系统或 CUDA 版本,正确的命令可以在 PyTorch 网站上找到。

我随后拍摄了一些收据的照片。您可以使用自己的收据,但如果您不想使用,可以使用我在 Google Drive 上的收据,这些收据来自挪威超市。我把包含收据照片的文件夹称为ReceiptData,并将图像路径加载到变量中,使用以下代码:

img_path1="ReceiptData/20231016_180324.jpg"img_path2="ReceiptData/20231010_210904.jpg"img_path3="ReceiptData/20231014_182753.jpg"img_path4="ReceiptData/20230917_131726.jpg"img_path5="ReceiptData/20231002_190427.jpg"

我还喜欢有一个变量来表示我正在使用哪个收据,以提高可读性和方便在收据之间切换。

PATH_TO_USE=img_path2

要加载 EasyOCR,您可以使用以下行。请注意,如果您正在读取不同语言的文本,可以将no改为您希望的语言(例如,en用于英语)。您可以在 这个网站 上找到所有可用语言及其代码名称。另外,如果您不使用 GPU,可以将 gpu 设置为 False。

reader=easyocr.Reader(['no'],gpu=True)# this needs to run only once to load the model into memory

我随后读取了图像,将其转换为灰度以改善 OCR 性能,并运行了 OCR。此外,我还将 OCR 输出合并为一个字符串。

img=cv2.imread(PATH_TO_USE)img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)result=reader.readtext(img,detail=0)result_string=""foreleinresult:result_string+=ele+" "

如果您想查看收据,可以使用以下方式:

cv2.namedWindow('img',cv2.WINDOW_NORMAL)cv2.imshow("img",img)cv2.waitKey(0)cv2.destroyAllWindows()

恭喜,您现在已经成功从收据中提取了文本。请注意,一些 OCR 输出可能看起来像是无意义的,例如,一个收据的 OCR 输出的开头看起来像:Al rema 10@@ Salaskvittering REMA 1ooo GausdAL,这显然不是最优的。这种情况发生有几个原因,但主要原因是收据上的文字相当小,这使得 OCR 难以识别所有字符。然而,正如您将在本文后面看到的那样,OCR 仍然足够有效,可以成功从收据中提取项目。然而,值得注意的是,提高 OCR 质量应该是未来工作的优先事项。

使用 GPT-4o mini 进行信息提取

我花了很多时间尝试使用 Python 中的逻辑、正则表达式和类似的方法从收据中提取信息。然而,这些方法的缺点是它们难以处理 OCR 可以输出的各种输出。然而,像 GPT-4o mini 这样的大型语言模型已经彻底改变了这个过程,它们既能处理多样化的输入,又能输出结构化的响应。这使得大型语言模型非常适合我们想要完成的任务,即从收据的 OCR 输出中提取项目和价格。对于这篇文章,我将使用 GPT-4o mini,尽管许多其他 LLM 在这种情况下也是可行的。

首先,你应该在OpenAI上登录或创建一个账户。这将给你访问 OpenAI API 所需的 API 密钥。你还需要输入一种支付方式来支付 API 请求的费用。我建议尽快在你的账户上设置消费限额,因为人们很容易开始花费大量金钱。然而,在收据数据上使用 GPT-4o mini 相当便宜,你可以在OpenAI 的网站上查看完整的定价概述。

然后,你应该安全地存储 API。有几种方法可以做到这一点,但我只是创建了一个看起来像这样的constants.py文件:

OPEN_AI_API_KEY="123123123"

然后,你可以使用以下代码将密钥导入一个单独的文件:

fromconstantsimportOPEN_AI_API_KEY OPEN_AI_API_KEY=str(OPEN_AI_API_KEY)assertOPEN_AI_API_KEY.startswith("sk-")andOPEN_AI_API_KEY.endswith("123")client=OpenAI(api_key=OPEN_AI_API_KEY)

记得在断言中替换两个字符串以匹配你的 API 密钥。这个断言语句确保你正在使用正确的 API 密钥。

然后,你可以创建一个 OpenAI 客户端来发送 API 请求:

fromopenaiimportOpenAIimportos client=OpenAI(api_key=OPEN_AI_API_KEY)

你可以使用以下方式发送 API 请求:

MODEL="gpt-4o-mini"defprompt_gpt(prompt):returnclient.chat.completions.create(model=MODEL,messages=[{"role":"system","content":"You are a helpful assistant."},{"role":"user","content":prompt}]).choices[0].message.content

我接着创建了一个以下代码的提示。找到一个有效的提示很难,在处理这个过程中,我特别困难的是 GPT-4o mini 提供了过长的答案。为了解决这个问题,我添加了两句话,一句是“只回复列表,不要其他”,另一句是“当然,以下是物品和价格列表”。最后一部分很有趣,因为我将响应的开头包含在提示本身中,我了解到这可以帮助避免 LLM 提供过长的解释,这在当前情况下是不希望的。

prompt=f"Given a string of text from an OCR of a receipt. Find each item and price in the receipt, and return with a list of tuples like this: [(item1, price1), (item2, price2), ...]. Only respond with the list, and nothing else. The string is:{result_string}"prompt+=" . Sure, here is the list of items and prices: "

然后,你可以用以下方式提示 GPT-4o mini:

response=prompt_gpt(prompt)

这些是我收到的示例响应:

# for image 'ReceiptData/20231010_210904.jpg'[("KylLING HotwiNGS","57,00"),("Iskaffe Hocca","18,90"),("TORTILLACHIP ZINGY","16,90"),("SøTPOTeT FRIES","37,00"),("Creamy PEANøTTSHeR","46,00"),("GluTEn FReE TORT","43,90"),("DIP TEX MEX STyLE","40,90")]# for image 'ReceiptData/20231016_180324.jpg'[('RISTO HOZZA _ 2PK',89.90),('SUPERHEL T , GROYBRøP',35.00),('B#REPOSE',25.00),('Dr Oetker',26.97)]# for image 'ReceiptData/20231002_190427.jpg'[('TøRKEDE APRIKOSER',29.90),('MANDLER',10.90),('Couscous',22.40),('FISKEBURGER HYS8TO',53.90),('AVOCADO 2PK',40.00),('GRøNNKÅL',0.00),('BROKKOLI',0.00),('GULROT BEGER 75OGR',3.00)]

查看结果

在设置好所有从收据中提取信息的代码后,是时候审查这个方法的效果了。我将使用定性方法,单独查看一些收据来判断信息提取的效果。我将审查上面显示的 3 个图像。

第一张收据

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7ceeb97cfbcc24bb35bd99e1fa50389d.png

要审查的第一张收据。图片由作者提供。

对于这份收据,你可以看到信息提取管道能够正确地提取出所有项目。我认为这相当令人印象深刻,因为图像并不特别清晰,而且图像中有很多不属于收据的背景。不幸的是,项目名称中存在一些拼写错误,尽管我认为在这个上下文中这是可以接受的,因为你仍然可以很容易地理解这是什么项目。

第二份收据

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/07ec6354b016e02cae31209bbcc18511.png

第二份收据供审查。图片由作者提供。

在这份收据上,信息提取管道遇到了困难。前两项和价格是正确的,但模型对bærepose(这是因为 OCR 无法选择正确的项目价格)给出了错误的价格,这混淆了 LLM。收据项目部分的最后一行是第一项的折扣,LLM 无法理解,并错误地输出这是一个单独的项目。我认为这是可以接受的;然而,由于模型难以理解最后一行是不同项目的折扣而不是项目本身,这可能会造成困难。

第三份收据

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/eef95dc91722a4e28023989511b6dd79.png

第三份收据供审查。图片由作者提供。

对于这份收据,管道在前四项表现良好,但不幸的是,在剩下的四项上失败了。考虑到图像更清晰,背景噪声更少,这份收据应该比前两份更容易,但实际上并非如此。我查看了这份收据的 OCR 输出,以了解错误从何而来。前四项的输出是清晰且正确的,而模型突然在最后四项上失败,显示了错误的 OCR 输出可能会对 GPT-4o mini 造成重大问题。

理解如何改进管道

为了改进管道,我们必须了解其弱点。如前所述,问题似乎出在 OCR 上。为了进一步调查,我们将更深入地研究 OCR 输出。EasyOCR 中的 OCR 包括两个步骤。第一步被称为文本检测,它检测图像中存在文本的区域。这是通过使用边界框标记带文本的区域来完成的。第二步被称为*文本识别,给定一个包含文本的边界框,它将输出边界框中的文本。因此,本文实现的信息提取管道的问题可能出在这两个步骤中的任何一个。

首先,我们来看看文本识别,我们通过打印出 OCR 找到的边界框来实现这一点。你可以用以下代码来做这件事。首先,运行 OCR 并让函数返回边界框(这是通过将 detail 设置为 1 而不是我们之前设置的 0 来实现的)

result2=reader.readtext(img,detail=1)

然后,您可以使用以下命令打印出您图像的边界框:

# Loop through the results and draw bounding boxes on the original imagefor(bbox,text,prob)inresult2:top_left=tuple(bbox[0])bottom_right=tuple(bbox[2])# Draw the bounding box on the original imagecv2.rectangle(img,top_left,bottom_right,(0,255,0),2)# Green box with thickness 2# Optionally, put the recognized text on the original imagecv2.putText(img,text,(top_left[0],top_left[1]-10),cv2.FONT_HERSHEY_SIMPLEX,0.8,(0,255,0),2)# Now resize the image to a smaller sizescale_percent = 20 # percent of original sizewidth=int(img.shape[1]*scale_percent/100)height=int(img.shape[0]*scale_percent/100)dim=(width,height)# Resize the imageresized_img=cv2.resize(img,dim,interpolation=cv2.INTER_AREA)# Save or display the resized image with bounding boxescv2.imwrite('output_image_with_boxes.jpg',resized_img)cv2.imshow('Resized Image with Bounding Boxes',resized_img)cv2.waitKey(0)cv2.destroyAllWindows()

对于第三个收据,返回了以下收据。您可以看到,模型在读取最后四项的价格时遇到了困难。这导致文本识别步骤表现不佳,进而使得 GPT-4o mini 在提供收据上物品和价格准确响应时遇到困难。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/6a73bba5bdc00a6016be8f2ada214318.png

在 EasyOCR 文本识别步骤之后打印出第三个收据。您可以看到,模型在处理最后四项的价格时遇到了困难,导致出现了我们在第二个收据中看到的错误。图片由作者提供。

如果您重复对第二个收据的步骤,同样的问题也会出现。

解决这个问题主要有两种方法。第一步是拍摄更清晰的收据照片,使 OCR 更容易读取文本。然而,我认为第三个收据的照片已经很清晰,OCR 应该能够读取它。另一种主要方法是改进 OCR,无论是通过使用不同的 OCR 引擎(例如,PaddleOCR,Tesseract,或者像 AWS Textract 这样的付费 OCR 服务)还是通过微调 OCR,正如我在关于微调 EasyOCR 文本识别部分的文章中展示的那样。请注意,在处理这个项目时,我尝试了 PaddleOCR 和 Tesseract,它们的表现都低于 EasyOCR。

最后,我也测试了 Amazon Textract 选项,以查看其有效性。以下是第二个收据的结果,您可以看到,Amazon Textract 实际上完美地定位了所有文本,使其成为从收据中提取文本的一个非常有效的选项。在下一节中,我将 AWS Textract 实施到管道中,以查看应用程序的工作效果如何。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/35ec1dc78eaf10ec6e469c2207a5376a.png

这张图片展示了 AWS Textract 如何读取收据。正如您所看到的,边界框几乎完美地包围了文字,显示了 AWS Textract 的有效性。图片由作者提供。

尝试使用 Textract 改进的解决方案

为了了解从收据中提取信息的效果如何,我将使用 AWS Textract 进行 OCR,而不是 EasyOCR。通常,我更愿意在本地使用 OCR,因为这让我能更好地控制整个过程,而且 AI 的乐趣之一就是自己工作在模型上,而不仅仅是调用 API。然而,我想看看付费 OCR API 服务在这种情况下表现如何。使用 AWS Textract 需要设置 AWS 账户以获取访问密钥来调用 Textract API。请注意,AWS 的初始设置可能有点繁琐,主要是因为安全原因,但我向您保证,正确设置是值得您花时间的。这是因为您学会了如何设置 AWS,这是一个流行的云服务提供商,并确保了您密钥的安全性,这是一个重要的维护实践,尤其是在您开发一个拥有大量用户的应用程序时。在这里我不会提供设置账户的教程,但 AWS 为这个过程编写了一些高质量的文档,并且还有大量关于这个主题的文章。

Textract 服务也非常便宜,在撰写本文时,每月前一百万页的价格为 1.5 美元/1000 页,超过一百万页的价格为 0.6 美元/1000 页。如果您使用 detect document text API,AWS 免费层每月还提供 1000 页免费页面。

在您设置了访问凭证之后,您可以使用以下代码使用 Textract API。首先,一些导入。请注意,我把我的凭证存储在一个名为 constants*.py*的单独文件中。

importboto3fromioimportBytesIOfromconstantsimportAWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGIONimportos

然后,您必须创建一个客户端来调用 API。

defget_aws_textract_client():returnboto3.client('textract',aws_access_key_id=AWS_ACCESS_KEY_ID,aws_secret_access_key=AWS_SECRET_ACCESS_KEY,region_name=AWS_REGION)

我随后使用以下函数来调用 API。

defget_textract_text_from_image(client,image_path):assertos.path.exists(image_path),f"Image file not found:{image_path}"withopen(image_path,'rb')asdocument:img=bytearray(document.read())# Call Amazon Textractresponse=client.detect_document_text(Document={'Bytes':img})returnresponsedefextract_text_from_response(response):result_string=""forblockinresponse["Blocks"]:ifblock["BlockType"]=="WORD"orblock["BlockType"]=="LINE":result_string+=block["Text"]+" "returnresult_string

然后我用以下行调用这两个函数

response=get_textract_text_from_image(client,PATH_TO_USE)result_string=extract_text_from_response(response)

然后,我为第三个收据运行了这个程序,并提示 GPT-4o mini 使用提取的文本,得到了以下结果:

[('TORKEDE APRIKOSER',29.90),('MANDLER',10.90),('COUSCOUS',22.40),('FISKEBURGER HYS&TO',53.90),('AVOCADO 2PK 320G',34.90),('GRONNKAL 150G',24.90),('BROKKOLI',24.90),('GULROT BEGER 750GR',24.90)]

如您所见,AWS Textract 和 GPT-4o mini 可以正确地从收据中提取所有项目及其价格,除了最后一个项目的价格不正确。我也尝试了第二个收据,得到的响应是:

[('RISTO. MOZZA. 2PK 15%',89.90),('SUPERHELT GROVBROD 15%',35.00),('BAREPOSE 80% RESIR 25%',4.25),('30% Dr. Oetker',-26.97)]

在这种情况下,AWS Textract 和 GPT-4o mini 可以完美地提取所有项目和价格。请注意,GPT-4o mini 返回的最后一个项目价格是负数,我认为这是可以接受的,应该在应用程序的前端处理。

结论

在这篇文章中,我向您展示了如何开发一个信息提取流程,以从收据中检索项目和价格。我们首先通过实现 EasyOCR 从收据中提取文本,然后使用 GPT-4o mini 根据 OCR 输出提供项目和价格。接着,我们对三张不同的收据进行了结果审查。审查显示,该流程对于某些项目表现良好,能够提取正确的项目和价格,尽管项目名称存在一些拼写错误。然而,对于其他项目,该流程完全失败,这主要可以归因于 OCR 错误。除了 EasyOCR,我还测试了 Tesseract OCR 和 PaddleOCR,它们在这篇文章的三张收据上并没有提供更好的结果。我们设置了 AWS Textract 来处理 OCR 错误,它比 EasyOCR、Tesseract 和 PaddleOCR 提供了更好的结果。通过结合使用 AWS Textract 和 GPT-4o mini,我们能够相当准确地从收据中导出项目和价格。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询