丨資料派THU
文檔解析涉及檢查文檔中的資料并提取有用的資訊。,它可以通過自動化減少了大量的手動工作。一種流行的解析政策是将文檔轉換為圖像并使用計算機視覺進行識别。而文檔圖像分析(Document Image Analysis)是指從文檔的圖像的像素資料中擷取資訊的技術,在某些情況下,預期結果應該是什麼樣的沒有明确的答案(文本、圖像、圖表、數字、表格、公式……)。
OCR (Optical Character Recognition,光學字元識别)是通過計算機視覺對圖像中的文本進行檢測和提取的過程。它是在第一次世界大戰期間發明的,當時以色列科學家伊曼紐爾·戈德堡(Emanuel Goldberg)發明了一台能讀取字元并将其轉換為電報代碼的機器。到了現在該領域已經達到了一個非常複雜的水準,混合圖像處理、文本定位、字元分割和字元識别。基本上是一種針對文本的對象檢測技術。
在本文中我将展示如何使用OCR進行文檔解析。我将展示一些有用的Python代碼,這些代碼可以很容易地用于其他類似的情況(隻需複制、粘貼、運作),并提供完整的源代碼下載下傳。
這裡将以一家上市公司的PDF格式的财務報表為例(連結如下)。
https://s2.q4cdn.com/470004039/files/doc_financials/2021/q4/_10-K-2021-(As-Filed).pdf
檢測和提取該PDF中的 文本、圖形和表格
環境設定
文檔解析令人煩惱的部分是,有太多的工具用于不同類型的資料(文本、圖形、表格),但沒有一個能夠完美地工作。下面是一些最流行方法和軟體包:
- 以文本方式處理文檔:用PyPDF2提取文本,用Camelot或TabulaPy提取表,用PyMuPDF提取圖形。
- 将文檔轉換為圖像(OCR):使用pdf2image進行轉換,使用PyTesseract以及許多其他的庫提取資料,或者隻使用LayoutParser。
也許你會問:“為什麼不直接處理PDF檔案,而要把頁面轉換成圖像呢?”你可以這麼做。這種政策的主要缺點是編碼問題:文檔可以采用多種編碼(即UTF-8、ASCII、Unicode),是以轉換為文本可能會導緻資料丢失。是以為了避免産生該問題,我将使用OCR,并用pdf2image将頁面轉換為圖像,需要注意的是PDF渲染庫Poppler是必需的。
# with pip
pip install python-poppler
# with conda
conda install -c conda-forge poppler
你可以很容易地讀取檔案:
# READ AS IMAGE
import pdf2imagedoc = pdf2image.convert_from_path("doc_apple.pdf")
len(doc) #<-- check num pages
doc[0] #<-- visualize a page
跟我們的截圖一模一樣,如果想将頁面圖像儲存在本地,可以使用以下代碼:
# Save imgs
import osfolder = "doc"
if folder not in os.listdir():
os.makedirs(folder)p = 1
for page in doc:
image_name = "page_"+str(p)+".jpg"
page.save(os.path.join(folder, image_name), "JPEG")
p = p+1
最後,我們需要設定将要使用的CV引擎。LayoutParser似乎是第一個基于深度學習的OCR通用包。它使用了兩個著名的模型來完成任務:
Detection: Facebook最先進的目标檢測庫(這裡将使用第二個版本Detectron2)。
pip install layoutparser torchvision && pip install "git+https://github.com/facebookresearch/[email protected]#egg=detectron2"
Tesseract:最著名的OCR系統,由惠普公司在1985年建立,目前由谷歌開發。
pip install "layoutparser[ocr]"
現在已經準備好開始OCR程式進行資訊檢測和提取了。
import layoutparser as lp
import cv2
import numpy as np
import io
import pandas as pd
import matplotlib.pyplot as plt
檢測
(目标)檢測是在圖檔中找到資訊片段,然後用矩形邊框将其包圍的過程。對于文檔解析,這些資訊是标題、文本、圖形、表……
讓我們來看一個複雜的頁面,它包含了一些東西:
這個頁面以一個标題開始,有一個文本塊,然後是一個圖和一個表,是以我們需要一個經過訓練的模型來識别這些對象。幸運的是,Detectron能夠完成這項任務,我們隻需從這裡選擇一個模型,并在代碼中指定它的路徑。
我将要使用的模型隻能檢測4個對象(文本、标題、清單、表格、圖形)。是以,如果你需要識别其他東西(如方程),你就必須使用其他模型。
## load pre-trained model
model = lp.Detectron2LayoutModel(
"lp://PubLayNet/mask_rcnn_X_101_32x8d_FPN_3x/config",
extra_config=["MODEL.ROI_HEADS.SCORE_THRESH_TEST", 0.8],
label_map={0:"Text", 1:"Title", 2:"List", 3:"Table", 4:"Figure"})
## turn img into array
i = 21
img = np.asarray(doc[i])
## predict
detected = model.detect(img)
## plot
lp.draw_box(img, detected, box_width=5, box_alpha=0.2,
show_element_type=True)
結果包含每個檢測到的布局的細節,例如邊界框的坐标。根據頁面上顯示的順序對輸出進行排序是很有用的:
## sort
new_detected = detected.sort(key=lambda x: x.coordinates[1])
## assign ids
detected = lp.Layout([block.set(id=idx) for idx,block in
enumerate(new_detected)])## check
for block in detected:
print("---", str(block.id)+":", block.type, "---")
print(block, end='\n\n')
完成OCR的下一步是正确提取檢測到内容中的有用資訊。
提取
我們已經對圖像完成了分割,然後就需要使用另外一個模型處理分段的圖像,并将提取的輸出儲存到字典中。
由于有不同類型的輸出(文本,标題,圖形,表格),是以這裡準備了一個函數用來顯示結果。
'''
{'0-Title': '...',
'1-Text': '...',
'2-Figure': array([[ [0,0,0], ...]]),
'3-Table': pd.DataFrame,
}
'''
def parse_doc(dic):
for k,v in dic.items():
if "Title" in k:
print('\x1b[1;31m'+ v +'\x1b[0m')
elif "Figure" in k:
plt.figure(figsize=(10,5))
plt.imshow(v)
plt.show()
else:
print(v)
print(" ")
首先看看文字:
# load model
model = lp.TesseractAgent(languages='eng')
dic_predicted = {}
for block in [block for block in detected if block.type in ["Title","Text"]]:
## segmentation
segmented = block.pad(left=15, right=15, top=5,
bottom=5).crop_image(img)
## extraction
extracted = model.detect(segmented)
## save
dic_predicted[str(block.id)+"-"+block.type] =
extracted.replace('\n',' ').strip()
# check
parse_doc(dic_predicted)
再看看圖形報表
for block in [block for block in detected if block.type == "Figure"]:
## segmentation
segmented = block.pad(left=15, right=15, top=5,
bottom=5).crop_image(img)
## save
dic_predicted[str(block.id)+"-"+block.type] = segmented
# check
parse_doc(dic_predicted)
上面兩個看着很不錯,那是因為這兩種類型相對簡單,但是表格就要複雜得多。尤其是我們上看看到的的這個,因為它的行和列都是進行了合并後産生的。
for block in [block for block in detected if block.type == "Table"]:
## segmentation
segmented = block.pad(left=15, right=15, top=5,
bottom=5).crop_image(img)
## extraction
extracted = model.detect(segmented)
## save
dic_predicted[str(block.id)+"-"+block.type] = pd.read_csv(
io.StringIO(extracted) )
# check
parse_doc(dic_predicted)
正如我們的預料提取的表格不是很好。好在Python有專門處理表格的包,我們可以直接處理而不将其轉換為圖像。這裡使用TabulaPy 包:
import tabula
tables = tabula.read_pdf("doc_apple.pdf", pages=i+1)
tables[0]
結果要好一些,但是名稱仍然錯了,但是效果要比直接OCR好的多。
總結
本文是一個簡單教程,示範了如何使用OCR進行文檔解析。使用Layoutpars軟體包進行了整個檢測和提取過程。并展示了如何處理PDF文檔中的文本,數字和表格。
本文的源代碼:
https://github.com/mdipietro09/DataScience_ArtificialIntelligence_Utils/blob/master/computer_vision/example_ocr_parsing.ipynb
如果你安裝Tesseract有問題的話,請看這個文章
https://stackoverflow.com/questions/50951955/pytesseract-tesseractnotfound-error-tesseract-is-not-installed-or-its-not-i
編輯:于騰凱