python - 在 python lib 中导入和裁剪 jpeg 的快速方法
问题描述
我有一个 python 应用程序,它导入 200k+ 图像,裁剪它们,并将裁剪的图像呈现给 pyzbar 以解释条形码。裁剪很有帮助,因为图像上有多个条形码,并且当给定较小的图像时,大概 pyzbar 会更快一些。
目前我正在使用 Pillow 导入和裁剪图像。
平均而言,导入和裁剪图像需要 262 毫秒,而 pyzbar 需要 8 毫秒。
典型的运行时间约为 21 小时。
我想知道除了 Pillow 之外的库是否可以在加载/裁剪方面提供实质性改进。理想情况下,该库应该可用于 MacOS,但我也可以在虚拟 Ubuntu 机器上运行整个东西。
我正在开发一个可以在并行进程中运行的版本,这将是一个很大的改进,但如果我可以从不同的库中获得 25% 或更多的速度提升,我也会添加它。
解决方案
由于您没有提供示例图像,我制作了一个尺寸为 2544x4200、大小为 1.1MB 的虚拟文件,并在答案末尾提供。我制作了 1,000 张该图像的副本,并为每个基准测试处理了所有 1,000 张图像。
因为你只在评论区给出了你的代码,所以我接受了它,格式化它并尽我所能。我还把它放在一个循环中,这样它就可以处理许多文件,只调用一次 Python 解释器——当你有 20,000 个文件时,这变得很重要。
看起来像这样:
#!/usr/bin/env python3
import sys
from PIL import Image
# Process all input files so we only incur Python startup overhead once
for filename in sys.argv[1:]:
print(f'Processing: {filename}')
imgc = Image.open(filename).crop((0, 150, 270, 1050))
我的怀疑是我可以使用以下方法更快地做到这一点:
- GNU 并行,和/或
- pyvips
这是pyvips
您的代码的一个版本:
#!/usr/bin/env python3
import sys
import pyvips
import numpy as np
# Process all input files so we only incur Python startup overhead once
for filename in sys.argv[1:]:
print(f'Processing: {filename}')
img = pyvips.Image.new_from_file(filename, access='sequential')
roi = img.crop(0, 150, 270, 900)
mem_img = roi.write_to_memory()
# Make a numpy array from that buffer object
nparr = np.ndarray(buffer=mem_img, dtype=np.uint8,
shape=[roi.height, roi.width, roi.bands])
结果如下:
顺序原码
./orig.py bc*jpg
224 seconds, i.e. 224 ms per image, same as you
并行原码
parallel ./orig.py ::: bc*jpg
55 seconds
并行原始代码,但传递尽可能多的文件名
parallel -X ./orig.py ::: bc*jpg
42 seconds
顺序pyvips
./vipsversion bc*
30 seconds, i.e. 7x as fast as PIL which was 224 seconds
并行pyvips
parallel ./vipsversion ::: bc*
32 seconds
并行 pyvips,但传递尽可能多的文件名
parallel -X ./vipsversion ::: bc*
5.2 seconds, i.e. this is the way to go :-)
请注意,您可以使用homebrew在 macOS 上安装GNU Parallel:
brew install parallel
推荐阅读
- python - 数组在我的 pycharm 中没有以正确的方式运行
- c - C语言中如何修改环境变量
- flutter - Flutter 本地化:当我们在 dart 文件中键入代码时,在 intl_en.arb 中自动生成键值
- httpcontext - ihttpcontextaccessor.httpcontext.user.findfirst(claimtypes.nameidentifier).value 为空
- excel - 创建一个输入数量未知的函数
- google-drive-api - Google Add-on 脚本在调用 DriveApp getFolderById 或 getFileById 时引发服务器错误
- c++ - 这个临时对象什么时候被销毁?在进入函数之前还是在函数返回之后?
- c - 理解树的结构
- c++ - glCullFace 工作不正常,你有答案吗?
- python - 如何将在 tkinter 中上传的图像放入函数中?