我正在使用wand和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服务器。但是,因为即使是一个13.7 MB的pdf文件,image_pdf也会增长到大约4gb,所以它被oom杀手所阻止。我想尝试减少魔杖和ImageMagick使用的内存,而不是支付更高的内存。由于它已经异步,我不介意增加计算时间。我已经略过了这个:http://www.imagemagick.org/Usage/files/#massive,但我不确定它是否可以用魔杖实现。另一种可能的解决方法是一次在一个页面中打开一个pdf的方法,而不是一次将完整的图像放入RAM中。或者,我怎么能直接使用python与ImageMagick接口,以便我可以使用这些内存限制技术?
答案 0 :(得分:2)
请记住wand库与MagickWand
API集成,然后将PDF编码/解码工作委托给ghostscript
。 MagickWand
和& ghostscript
分配了额外的内存资源,最好在每个任务结束时解除分配。但是,如果例程由python初始化并由变量保存,那么它可能会引入内存泄漏。
以下是确保正确管理内存的一些提示。
对所有Wand分配使用with
上下文管理。这将确保所有资源都通过__enter__
& __exit__
管理处理程序。
为传递数据而避免blob
创建。在创建文件格式blob时,MagickWand将分配额外的内存来复制&对图像进行编码,除了原始的wand实例之外,python还将保存结果数据。通常在开发环境中很好,但在生产环境中可能会迅速失控。
避免Image.sequence
。这是另一个拷贝繁重的例程,导致python持有大量内存资源。请记住,ImageMagick可以非常好地管理图像堆栈,因此如果您不重新排序/操作单个帧,最好使用MagickWand方法&不涉及python。
每个任务都应该是一个独立的过程,并且可以在完成时干净地关闭。对于作为队列工作者的celery
来说,这不应该是一个问题,但值得仔细检查线程/工作者配置+文档。
注意解决问题。 pdf分辨率为300 @ 16Q会产生巨大的光栅图像。使用许多OCR(tesseract / opencv)技术,第一步是将入站数据预处理为删除额外/不需要的颜色/通道/数据/& tc。
这是我如何处理这个问题的一个例子。注意,我将利用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)
当然你的milage可能会有所不同。如果您对subprocess感到满意,则可以执行gs
&直接tesseract
,并消除所有python包装器。
答案 1 :(得分:0)
@emcconville中的代码有效,并且我的临时文件夹不再充满magick- *文件
我需要导入ctype而不是cstyle
我也收到@kerthik提到的错误
通过保存图像并再次加载来解决它,也可以将其保存到内存中
from PIL import Image as PILImage
...
context.save(filename="temp.jpg")
text = pytesseract.image_to_string(PILImage.open("temp.jpg"))`
编辑 我在How to convert wand.image.Image to 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")
答案 2 :(得分:0)
我还遇到了内存泄漏问题。经过一些研究并调整了代码实现,我的问题得到解决。 我基本上可以使用 with 和 destroy()函数正常工作。
在某些情况下,我可以使用和来打开和读取文件,如下例所示:
{
"ignore": ["js/framework/**/*.js","config.js"],
"/": {
"plugins": ["resolve-linked-dependencies"],
".babelrc": {
"presets": ["liferay-standard"]
},
"post-plugins": ["namespace-packages", "inject-imports-dependencies"]
},
"*": {
"plugins": ["replace-browser-modules"],
".babelrc": {
"plugins":[ ["namespace-amd-define", {
"namespace": "Liferay.Loader"
}]
],
"presets": ["liferay-standard"]
},
"post-plugins": ["namespace-packages", "inject-peer-dependencies"]
}
}
在这种情况下,正确使用内存和tmp文件。
在另一种情况下,我必须使用 destroy()函数,最好在 try / finally 块中,如下所示:
Liferay.Loader.define('sigerb-web$lodash-amd@4.17.15/_arrayShuffle',
['module', 'exports', 'require'], function (module, exports, require)
{
var define = undefined;
define(['./_copyArray', './_shuffleSelf'], function (copyArray, shuffleSelf) { ...
第二种情况是一个示例,其中我不能使用和,因为我不得不通过序列来迭代页面,因此,我已经打开了文件并正在迭代您的页面。
这种解决方案的组合解决了我的内存泄漏问题。
答案 3 :(得分:0)
我遇到了类似的问题。
发现此页面有趣: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的memory-profiler确认它可以正常工作。