pyocr с tesseract не хватает памяти

Я сделал скрипт для пакетной обработки PDF-сканов в текст с помощью tesseract и pyocr. Код ниже. Проблема в том, что при обработке большого количества файлов, например, 20+, в какой-то момент сценарию просто не хватает памяти и происходит сбой с OSError. В настоящее время я сделал это так, чтобы он мог плавно наверстать упущенное после ручного перезапуска, но эти ручные перезапуски утомительны.

Поскольку pyocr для меня в основном черный ящик, я попытался обернуть скрипт в другие скрипты Python, которые перезапустили бы его при сбое, но все они, кажется, выходят из строя из-за этой ошибки, освобождая память только тогда, когда завершается каждый связанный скрипт.

Единственное другое решение, которое я могу придумать, - это создать полностью внешнюю оболочку, которая проверяла бы, работает ли скрипт, и перезапускала бы его, если нет, И все еще есть необработанные файлы.

Но, может быть, есть лучшее решение? Или, может быть, я сделал хромой код, который можно улучшить, чтобы избежать этих сбоев памяти? (Кроме того, что я знаю, что это хромает, но работает достаточно хорошо :)).

from io import BytesIO
from wand.image import Image
from PIL import Image as PI
import pyocr
import pyocr.builders
import io
import os
import os.path
import ast


def daemon_ocr(tool, img, lang):
    txt = tool.image_to_string(
        PI.open(BytesIO(img)),
        lang=lang,
        builder=pyocr.builders.TextBuilder()
    )
    return txt


def daemon_wrap(image_pdf, tool, lang, iteration):
    print(iteration)
    req_image = []
    final_text = ''
    image_pdf_bckp = image_pdf
    image_jpeg = image_pdf.convert('jpeg')

    for img in image_jpeg.sequence:
        img_page = Image(image=img)
        req_image.append(img_page.make_blob('jpeg'))

    for img in req_image:
        txt = daemon_ocr(tool, img, lang)
        final_text += txt + '\n '
    if 'работ' not in final_text and 'фактура' not in final_text and 'Аренда' not in final_text and 'Сумма' not in final_text\
            and 'аренде' not in final_text and 'товара' not in final_text:
        if iteration < 5:
            iteration += 1
            image_pdf = image_pdf.rotate(90)
            final_text = daemon_wrap(image_pdf_bckp, tool, lang, iteration)
    return final_text


def daemon_pyocr(food):
    tool = pyocr.get_available_tools()[0]
    lang = tool.get_available_languages()[0]
    iteration = 1
    image_pdf = Image(filename='{doc_name}'.format(doc_name=food), resolution=300)
    final_text = daemon_wrap(image_pdf, tool, lang, iteration)
    return final_text


files = [f for f in os.listdir('.') if os.path.isfile(f)]
output = {}
print(files)
path = os.path.dirname(os.path.abspath(__file__))
if os.path.exists('{p}/output'.format(p=path)):
    text_file = open("output", "a")
    first = False
else:
    text_file = open("output", "w")
    first = True

for f in files:
    if f != 'ocr.py' and f != 'output':
        try:
            output[f] = daemon_pyocr(f)
            print('{f} done'.format(f=f))
            if first:
                text_file.write(str(output)[1:-1])
                first = False
            else:
                text_file.write(', {d}'.format(d=str(output)[1:-1]))
            output = {}
            os.rename('{p}/{f}'.format(p=path, f=f), "{p}/done/{f}".format(p=path, f=f))
        except OSError:
            print('{f} failed: not enough memory.'.format(f=f))

person Vémundr    schedule 28.03.2017    source источник


Ответы (1)


У меня тоже была такая проблема, наконец-то разобрался. Настоящая проблема не с pyocr, а с sequence из wand.image.Image.

Вы можете использовать метод destroy() объекта Image для освобождения памяти. Всегда используйте оператор with при работе с жезлом.

Вопросы по этой теме уже есть здесь и здесь

Вот мой код, который преобразует PDF-файл в изображение, если это вам поможет.

def convert_pdf_to_image_blob(pdf):
    req_image = []
    with WI(filename=pdf, resolution=150) as image_jpeg:
        image_jpeg.compression_quality = 99
        image_jpeg = image_jpeg.convert('jpeg')

        for img in image_jpeg.sequence:
            with WI(image=img) as img_page:
                req_image.append(img_page.make_blob('jpeg'))
    image_jpeg.destroy()  # frees memory used by Image object. 
    return req_image

Спасибо

person akhilsp    schedule 05.06.2017
comment
Спасибо, что поделился. Задача, для которой я это делал, на данный момент ушла, но я определенно собираюсь попробовать это решение, просто чтобы заставить его работать. - person Vémundr; 12.07.2017
comment
ОШИБКА: image_jpeg вы не можете его уничтожить, потому что он уже закрыт with. - person Karthik; 15.05.2018