在python库中导入和裁剪jpeg的快速方法
我有一个python应用程序,它导入200k+个图像,对它们进行裁剪,并将裁剪后的图像呈现给pyzbar以解释条形码。裁剪很有帮助,因为图像上有多个条形码,而且当给定较小的图像时,pyzbar可能会更快一些 目前我正在使用枕头导入和裁剪图像 导入和裁剪图像平均需要262毫秒,pyzbar需要8毫秒 典型的运行时间约为21小时在python库中导入和裁剪jpeg的快速方法,python,image-processing,jpeg,Python,Image Processing,Jpeg,我有一个python应用程序,它导入200k+个图像,对它们进行裁剪,并将裁剪后的图像呈现给pyzbar以解释条形码。裁剪很有帮助,因为图像上有多个条形码,而且当给定较小的图像时,pyzbar可能会更快一些 目前我正在使用枕头导入和裁剪图像 导入和裁剪图像平均需要262毫秒,pyzbar需要8毫秒 典型的运行时间约为21小时 我想知道除了枕头以外的图书馆是否可以在加载/裁剪方面提供实质性的改进。理想情况下,这个库应该可以用于MacOS,但我也可以在虚拟Ubuntu机器上运行整个程序 我正在开发一
我想知道除了枕头以外的图书馆是否可以在加载/裁剪方面提供实质性的改进。理想情况下,这个库应该可以用于MacOS,但我也可以在虚拟Ubuntu机器上运行整个程序 我正在开发一个可以在并行进程中运行的版本,这将是一个很大的改进,但如果我可以从另一个库中获得25%或更多的速度提升,我也会补充这一点。你可以看看,在解码大JPEG图像时,它是一个Python包装,具有惊人的快速缩放(1/2,1/4,1/8),返回的numpy.ndarray便于图像裁剪。此外,JPEG图像编码速度也非常显著
from turbojpeg import TurboJPEG
# specifying library path explicitly
# jpeg = TurboJPEG(r'D:\turbojpeg.dll')
# jpeg = TurboJPEG('/usr/lib64/libturbojpeg.so')
# jpeg = TurboJPEG('/usr/local/lib/libturbojpeg.dylib')
# using default library installation
jpeg = TurboJPEG()
# direct rescaling 1/2 while decoding input.jpg to BGR array
in_file = open('input.jpg', 'rb')
bgr_array_half = jpeg.decode(in_file.read(), scaling_factor=(1, 2))
in_file.close()
# encoding BGR array to output.jpg with default settings.
out_file = open('output.jpg', 'wb')
out_file.write(jpeg.encode(bgr_array))
out_file.close()
还提供了适用于macOS和Linux的libjpeg-turbo预构建二进制文件。由于您没有提供示例图像,我制作了一个尺寸为2544x4200、大小为1.1MB的虚拟文件,并在回答的末尾提供了该文件。我制作了1000份该图像的副本,并为每个基准处理了所有1000张图像 由于您只在评论区提供了代码,所以我将其进行了格式化,并尽我所能充分利用了它。我还将它放在一个循环中,这样它就可以只调用一次Python解释器就可以处理多个文件——当您有20000个文件时,这一点就变得非常重要 看起来是这样的:
#!/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])
结果如下:
顺序原始码
并行源代码
并行原始代码,但传递尽可能多的文件名
顺序pyvips
平行pyvips
并行pyvip,但传递尽可能多的文件名
请注意,您可以使用自制在macOS上安装GNU Parallel:
brew install parallel
Python不是用于高性能计算的通用语言。也许如果你发布了一些代码,我们可以对其效率进行评论,并且在不知道图像大小的情况下,我们无法真正说出262毫秒是慢还是快,尽管直觉反应很慢。你也试过OpenCV甚至ImageMagick的批处理功能吗?“我想知道除了Pillow之外的库是否可以在加载/裁剪方面提供实质性的改进。”你可以用不同的库来测试它。@KenY-N建议我发布一些代码。这里是:imgc=Image.open(infle.crop((0,150,270,1050))输入文件都是2544x4200像素的JPG,范围从500KB到1.5MB,取决于页面上有多少空白。这一步的平均时间是250毫秒。@Trilarion:显然我可以。我希望有人能分享他们的经历。太好了!使用
new\u from\u file(filename,access='sequential')
,您可以使pyvips one更快一点。这只会费事解码裁剪区域。@jcupitt非常好,谢谢!我将稍后或明天试用,然后报告。哦,工作方式:顺序模式将图像从源文件流式传输到目标内存区域。因为jpg是按需解压的,一旦需求停止,解压将被放弃。因此,在这种情况下,它将只解压缩到第1200行,而忽略其他3000行。@jcupitt Mmmm,这显著改进了顺序和并行-X
,但使中间的一行更糟。。。不确定发生了什么。哦,好的,是的,每次调用只裁剪一个图像,开始/停止时间占主导地位。我在10秒内看到1000种作物,其中有连续的PyVIP,2.6秒有平行的PyVIP。
parallel ./orig.py ::: bc*jpg
55 seconds
parallel -X ./orig.py ::: bc*jpg
42 seconds
./vipsversion bc*
30 seconds, i.e. 7x as fast as PIL which was 224 seconds
parallel ./vipsversion ::: bc*
32 seconds
parallel -X ./vipsversion ::: bc*
5.2 seconds, i.e. this is the way to go :-)
brew install parallel