在python lib中导入和裁剪jpeg的快速方法

Wes*_*esR 4 python jpeg image-processing

我有一个 python 应用程序,它导入 200k+ 图像,裁剪它们,并将裁剪后的图像呈现给 pyzbar 以解释条形码。裁剪有帮助,因为图像上有多个条形码,而且在给定较小的图像时,pyzbar 可能会快一些。

目前我正在使用 Pillow 导入和裁剪图像。

平均而言,导入和裁剪图像需要 262 毫秒,而 pyzbar 需要 8 毫秒。

典型的运行时间约为 21 小时。

我想知道 Pillow 以外的库是否可以在加载/裁剪方面提供实质性的改进。理想情况下,该库应该可用于 MacOS,但我也可以在虚拟 Ubuntu 机器上运行整个程序。

我正在开发一个可以在并行进程中运行的版本,这将是一个很大的改进,但如果我可以从不同的库中获得 25% 或更多的速度提升,我也会添加它。

Mar*_*ell 6

由于您没有提供示例图像,我制作了一个尺寸为 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))
Run Code Online (Sandbox Code Playgroud)

我怀疑我可以使用以下方法加快速度:

  • GNU 并行,和/或
  • 小伙伴们

这是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])
Run Code Online (Sandbox Code Playgroud)

结果如下:

顺序原码

./orig.py bc*jpg
224 seconds, i.e. 224 ms per image, same as you
Run Code Online (Sandbox Code Playgroud)

并行原码

parallel ./orig.py ::: bc*jpg
55 seconds
Run Code Online (Sandbox Code Playgroud)

并行原始代码但传递尽可能多的文件名

parallel -X ./orig.py ::: bc*jpg
42 seconds   
Run Code Online (Sandbox Code Playgroud)

顺序 pyvips

./vipsversion bc*
30 seconds, i.e. 7x as fast as PIL which was 224 seconds
Run Code Online (Sandbox Code Playgroud)

平行pyvips

parallel ./vipsversion ::: bc*
32 seconds
Run Code Online (Sandbox Code Playgroud)

并行 pyvips 但传递尽可能多的文件名

parallel -X ./vipsversion ::: bc*
5.2 seconds, i.e. this is the way to go :-)
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明


请注意,您可以使用homebrew在 macOS 上安装GNU Parallel

brew install parallel
Run Code Online (Sandbox Code Playgroud)


Lil*_*ang 2

您可能会看一下PyTurboJPEG ,它是libjpeg-turbo的 Python 包装器,在解码大型 JPEG 图像时具有极快的重新缩放(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()
Run Code Online (Sandbox Code Playgroud)

适用于 macOS 和 Linux 的 libjpeg-turbo 预构建二进制文件也可在此处获取。