从带图片的扫描PDF中提取文本?

9
我尝试从电脑创建的PDF中提取文本,它可以正常工作,但我无法从扫描的PDF中提取文本,例如这个链接中带有图像和多页的文件:https://docdro.id/gUuO21l,其中包含如下页面:

enter image description here

以下是我使用的代码:

# libraries
## split
from PyPDF2 import PdfFileWriter, PdfFileReader
## read 
import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
import io
# remove files
import os

# split in case there is several pages
def pdfspliter(filename):
    inputpdf = PdfFileReader(open(filename, "rb"))

    for i in range(inputpdf.numPages):
        output = PdfFileWriter()
        output.addPage(inputpdf.getPage(i))
        with open("document-page%s.pdf" % i, "wb") as outputStream:
            output.write(outputStream)
        pdfparser("document-page%s.pdf" % i)
        os.remove("document-page%s.pdf" % i)

# read a given page
def pdfparser(data):

    fp = open(data, 'rb')
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    # Create a PDF interpreter object.
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    # Process each page contained in the document.

    for page in PDFPage.get_pages(fp):
        interpreter.process_page(page)
        data =  retstr.getvalue()

    print(data)

if __name__ == '__main__':
    filename = sys.argv[1]
    pdfspliter(filename)

您能帮助提取这种文件中的文本吗?

使用Tesseract OCR进行更新

我尝试使用Python中的Tesseract OCR,它可以提取PDF文本的一些页面,但是需要很长时间,并且似乎在某个时候停止了:

# import the necessary packages
from PIL import Image
import pytesseract
import argparse
import cv2
import os
## split
from PyPDF2 import PdfFileWriter, PdfFileReader
# remove
import sys
# 
from pdf2image import convert_from_path
# import all files with a name
import glob

# functions
def pdfspliterimager(filename):
    inputpdf = PdfFileReader(open(filename, "rb"))
    for i in range(inputpdf.numPages):
        output = PdfFileWriter()
        output.addPage(inputpdf.getPage(i))
        with open("document-page%s.pdf" % i, "wb") as outputStream:
            output.write(outputStream)
        pages = convert_from_path("document-page%s.pdf" % i, 500)
        for page in pages:
            page.save('out%s.jpg'%i, 'JPEG')

        os.remove("document-page%s.pdf" % i)

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
    help="path to input image to be OCR'd")
ap.add_argument("-p", "--preprocess", type=str, default="thresh",
    help="type of preprocessing to be done")
args = vars(ap.parse_args())

# we test if it is a pdf
image_path = args["image"]
# if it is a pdf we convert it to an image
if image_path.endswith('.pdf'):
    pdfspliterimager(image_path)

# for all files with out in their name
file_names = glob.glob("out*")
for file_name in file_names:
    # load the image and convert it to grayscale
    image = cv2.imread(file_name)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # check to see if we should apply thresholding to preprocess the
    # image
    if args["preprocess"] == "thresh":
        gray = cv2.threshold(gray, 0, 255,
            cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

    # make a check to see if median blurring should be done to remove
    # noise
    elif args["preprocess"] == "blur":
        gray = cv2.medianBlur(gray, 3)

    # write the grayscale image to disk as a temporary file so we can
    # apply OCR to it
    filename = "{}.png".format(os.getpid())
    cv2.imwrite(filename, gray)

    # load the image as a PIL/Pillow image, apply OCR, and then delete
    # the temporary file
    text = pytesseract.image_to_string(Image.open(filename))
    os.remove(filename)
    print(text)

    # show the output images
    cv2.imshow("Image", image)
    cv2.imshow("Output", gray)
    cv2.waitKey(0)

1
Tesseract OCR可能会对你有所帮助。 - Leka Baper
@LekaBaper,我曾经努力将pdf转换为jpg,然后使用ocf,但是它确实解决了问题。当我对此满意时,我会发布答案。我的下一步是仅提取具有右上角括号的文本。 - Revolucion for Monica
但我仍然有问题:它似乎在某个点上停止了...也许是因为PDF本身的原因? - Revolucion for Monica
1个回答

1

使用Python对PDF文件进行OCR

,保留HTML。
import os
import io
from PIL import Image
import pytesseract
from wand.image import Image as wi
import gc

def Get_text_from_image(pdf_path):
    pdf=wi(filename=pdf_path,resolution=300)
    pdfImg=pdf.convert('jpeg')
    imgBlobs=[]
    extracted_text=[]
    for img in pdfImg.sequence:
        page=wi(image=img)
        imgBlobs.append(page.make_blob('jpeg'))
    for imgBlob in imgBlobs:
        im=Image.open(io.BytesIO(imgBlob))
        text=pytesseract.image_to_string(im,lang='eng')
        extracted_text.append(text)
    return ([i.replace("\n","") for i in extracted_text])   

我做了一点修改。

下面的代码按顺序将PDF的所有页面转换为图像,在代码末尾我销毁了图像序列,因为它会占用大量内存来处理。

def Get_text_from_image(pdf_path):
    import pytesseract,io,gc
    from PIL import Image
    from wand.image import Image as wi
    import gc
    """ Extracting text content from Image  """

    pdf=wi(filename=pdf_path,resolution=300)                                                                                                                
    pdfImg=pdf.convert('jpeg')                                                                                                                                                                              
    imgBlobs=[]
    extracted_text=[]
    try:        
        for img in pdfImg.sequence:
            page=wi(image=img)
            imgBlobs.append(page.make_blob('jpeg'))
            for i in range(0,5):
                [gc.collect() for i in range(0,10)]

        for imgBlob in imgBlobs:
            im=Image.open(io.BytesIO(imgBlob))
            text=pytesseract.image_to_string(im,lang='eng')
            text = text.replace(r"\n", " ")
            extracted_text.append(text)
            for i in range(0,5):
                [gc.collect() for i in range(0,10)]
        return (''.join([i.replace("\n"," ").replace("\n\n"," ") for i in extracted_text]))
        [gc.collect() for i in range(0,10)]
    finally:
        [gc.collect() for i in range(0,10)]
        img.destroy()

1
这是一个很好的最小代码片段,可以完成工作。在我看来,用空格替换换行符会是更好的默认行为,但return语句很容易自定义。 - Alex
2
我已经添加了垃圾回收和异常处理功能,以便释放内存中的图像序列。这将在一定程度上起作用,但不是100%的解决方案。Tesseract OCR无法完全保证精度,它取决于所扫描页面的质量。 - thrinadhn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接