簡體   English   中英

如何減少魔杖內存使用量?

[英]How to reduce wand memory usage?

我正在使用魔杖和 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)

我讓它在單獨的 ec2 服務器中的 celery 中運行。 但是,因為即使是 13.7 mb 的 pdf 文件,image_pdf 也會增長到大約 4gb,所以它被 oom 殺手阻止了。 我不想為更高的內存付費,而是想嘗試減少魔杖和 ImageMagick 使用的內存。 由於它已經是異步的,我不介意增加計算時間。 我瀏覽了這個: http : //www.imagemagick.org/Usage/files/#massive ,但我不確定它是否可以用魔杖實現。 另一種可能的解決方法是一次一頁地打開 pdf,而不是一次將完整圖像放入 RAM 中。 或者,我如何直接使用 python 與 ImageMagick 接口,以便我可以使用這些內存限制技術?

請記住, 庫與MagickWand API 集成,進而將 PDF 編碼/解碼工作委托給ghostscript MagickWandghostscript分配了額外的內存資源,並且最好在每個任務結束時解除分配。 但是,如果例程由 python 初始化並由變量保存,則很可能引入內存泄漏。

以下是確保正確管理內存的一些技巧。

  1. with所有 Wand 分配的上下文管理一起使用。 這將確保所有資源都通過__enter____exit__管理處理程序。

  2. 避免為傳遞數據而創建blob 創建文件格式的 blob 時,MagickWand 將分配額外的內存來復制和編碼圖像,除了原始魔杖實例之外,python 還將保存結果數據。 通常在開發環境中很好,但在生產環境中可能會很快失控。

  3. 避免Image.sequence 這是另一個需要大量復制的例程,導致 python 持有一堆內存資源。 記住 ImageMagick 很好地管理圖像堆棧,所以如果你不重新排序/操作單個幀,最好使用 MagickWand 方法而不涉及 python。

  4. 每個任務都應該是一個獨立的進程,並且可以在完成時干凈地關閉。 這對你作為隊列工作者的celery不應該是一個問題,但值得仔細檢查線程/工作者配置 + 文檔。

  5. 注意分辨率。 300 @ 16Q 的 pdf 分辨率會產生大量的光柵圖像。 使用許多 OCR(tesseract/opencv)技術,第一步是對入站數據進行預處理,以去除多余/不需要的顏色/通道/數據/等。

這是我將如何處理此問題的示例。 請注意,我將利用直接管理圖像堆棧,而無需額外的 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)

當然,您的里程可能會有所不同。 如果您對感到滿意,您可以直接執行gstesseract ,並消除所有 python 包裝器。

我也遇到了內存泄漏問題。 經過一些研究和調整代碼實現后,我的問題得到了解決。 我基本上使用withdestroy()函數正常工作。

在某些情況下,我可以使用with打開和讀取文件,如下例所示:

with Image(filename = pdf_file, resolution = 300) as pdf:

在這種情況下,使用 with,正確管理 memory 和 tmp 文件。

在另一種情況下,我不得不使用destroy()函數,最好在try / finally塊中,如下所示:

try:
    for img in pdfImg.sequence:
    # your code
finally:
    pdfImg.destroy()

第二種情況是我無法使用with的示例,因為我必須通過序列迭代頁面,因此,我已經打開了文件並正在迭代您的頁面。

這種解決方案組合解決了我的內存泄漏問題。

來自@emcconville 的代碼有效,我的臨時文件夾不再填滿 magick-* 文件

我需要導入 ctypes 而不是 cstyles

我也收到了@kerthik 提到的錯誤

通過保存圖像並再次加載來解決它,也可以正確地將其保存到內存中

from PIL import Image as PILImage

...
context.save(filename="temp.jpg")
text = pytesseract.image_to_string(PILImage.open("temp.jpg"))`

編輯我在如何將 wand.image.Image 轉換為 PIL.Image?

img_buffer = np.asarray(bytearray(context.make_blob(format='png')),dtype='uint8')
bytesio = io.BytesIO(img_buffer)
text = ytesseract.image_to_string(PILImage.open(bytesio),lang="dan")

我遇到了類似的問題。

發現這個頁面很有趣: http : //www.imagemagick.org/script/architecture.php#tera-pixel

以及如何通過魔杖限制 ImageMagick 使用的內存量: http : //docs.wand-py.org/en/latest/wand/resource.html

只需添加如下內容:

from wand.resource import limits

# Use 100MB of ram before writing temp data to disk.
limits['memory'] = 1024 * 1024 * 100

它可能會增加計算時間(但像你一樣,我不介意太多)而且我實際上沒有注意到這么多差異。

我使用 Python 的內存分析器確認它按預期工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM