如何减少魔杖内存使用量?

Jus*_*uhl 5 python imagemagick amazon-ec2 wand python-tesseract

我正在使用魔杖和 pytesseract 将 pdf 的文本上传到 django 网站,如下所示:

image_pdf = Image(blob=read_pdf_file, resolution=300)
image_png = image_pdf.convert('png')

req_image = []
final_text = []

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

for img in req_image:
    txt = pytesseract.image_to_string(PI.open(io.BytesIO(img)).convert('RGB'))
    final_text.append(txt)

return " ".join(final_text)
Run Code Online (Sandbox Code Playgroud)

我让它在单独的 ec2 服务器中的 celery 中运行。然而,因为即使是 13.7 mb 的 pdf 文件,image_pdf 也会增长到大约 4gb,所以它被 oom 杀手阻止了。我不想为更高的内存付费,而是想尝试减少魔杖和 ImageMagick 使用的内存。由于它已经是异步的,我不介意增加计算时间。我浏览了这个:http : //www.imagemagick.org/Usage/files/#massive,但我不确定它是否可以用魔杖实现。另一种可能的解决方法是一次一页地打开 pdf,而不是一次将完整图像放入 RAM 中。或者,我如何直接使用 python 与 ImageMagick 接口,以便我可以使用这些内存限制技术?

emc*_*lle 4

请记住,库与 API 集成MagickWand,然后将 PDF 编码/解码工作委托给ghostscript. 两者MagickWandghostscript分配了额外的内存资源,并最好在每个任务结束时取消分配。但是,如果例程由 python 初始化并由变量保存,则很可能会引入内存泄漏。

以下是一些确保正确管理内存的提示。

  1. with对所有 Wand 分配使用上下文管理。这将确保所有资源都通过__enter__管理__exit__处理程序。

  2. 避免blob为传递数据而创建。创建文件格式 blob 时,MagickWand 将分配额外的内存来复制和编码图像,并且 python 除了原始 wand 实例之外还将保存结果数据。通常在开发环境中表现良好,但在生产环境中可能会迅速失控。

  3. 避免Image.sequence。这是另一个大量复制的例程,并导致 python 占用大量内存资源。请记住,ImageMagick 可以很好地管理图像堆栈,因此,如果您不重新排序/操作单个帧,最好使用 MagickWand 方法而不涉及 python。

  4. 每个任务都应该是一个独立的进程,并且可以在完成后干净地关闭。celery对于作为队列工作人员的您来说,这不应该是问题,但值得仔细检查线程/工作人员配置+文档。

  5. 注意分辨率。300 @ 16Q 的 pdf 分辨率将产生巨大的光栅图像。对于许多 OCR(tesseract/opencv)技术,第一步是预处理传入数据以删除额外/不需要的颜色/通道/数据/&tc。

这是我将如何解决这个问题的一个例子。请注意,我将利用直接管理图像堆栈,无需额外的 python 资源。

import ctyles
from wand.image import Image
from wand.api import library

# Tell wand about C-API method
library.MagickNextImage.argtypes = [ctypes.c_void_p]
library.MagickNextImage.restype = ctypes.c_int

# ... Skip to calling method ...

final_text = []
with Image(blob=read_pdf_file, resolution=100) as context:
    context.depth = 8
    library.MagickResetIterator(context.wand)
    while(library.MagickNextImage(context.wand) != 0):
        data = context.make_blob("RGB")
        text = pytesseract.image_to_string(data)
        final_text.append(text)
return " ".join(final_text)
Run Code Online (Sandbox Code Playgroud)

当然,您的里程可能会有所不同。如果您熟悉,您可以直接执行gs& tesseract,并消除所有 python 包装器。