[英]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
。 MagickWand
和ghostscript
分配了額外的內存資源,並且最好在每個任務結束時解除分配。 但是,如果例程由 python 初始化並由變量保存,則很可能引入內存泄漏。
以下是確保正確管理內存的一些技巧。
with
所有 Wand 分配的上下文管理一起使用。 這將確保所有資源都通過__enter__
和__exit__
管理處理程序。
避免為傳遞數據而創建blob
。 創建文件格式的 blob 時,MagickWand 將分配額外的內存來復制和編碼圖像,除了原始魔杖實例之外,python 還將保存結果數據。 通常在開發環境中很好,但在生產環境中可能會很快失控。
避免Image.sequence
。 這是另一個需要大量復制的例程,導致 python 持有一堆內存資源。 記住 ImageMagick 很好地管理圖像堆棧,所以如果你不重新排序/操作單個幀,最好使用 MagickWand 方法而不涉及 python。
每個任務都應該是一個獨立的進程,並且可以在完成時干凈地關閉。 這對你作為隊列工作者的celery
不應該是一個問題,但值得仔細檢查線程/工作者配置 + 文檔。
注意分辨率。 300 @ 16Q 的 pdf 分辨率會產生大量的光柵圖像。 使用許多 OCR(tesseract/opencv)技術,第一步是對入站數據進行預處理,以去除多余/不需要的顏色/通道/數據/等。
這是我將如何處理此問題的示例。 請注意,我將利用ctypes直接管理圖像堆棧,而無需額外的 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)
當然,您的里程可能會有所不同。 如果您對subprocess感到滿意,您可以直接執行gs
和tesseract
,並消除所有 python 包裝器。
我也遇到了內存泄漏問題。 經過一些研究和調整代碼實現后,我的問題得到了解決。 我基本上使用with和destroy()函數正常工作。
在某些情況下,我可以使用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.