如何加快Pillow(Python)中图像的加载速度?

7

我希望使用pillow进行简单的手写图像识别,需要实时调用函数5-10次/秒。我正在加载图像,但只访问20^2个像素中的1个,因此不需要所有图像。我需要减少图像加载时间。

我从未使用过python图像库,希望获得所有建议。

from PIL import Image
import time

start = time.time()

im = Image.open('ir/IMG-1949.JPG')
width, height = im.size
px = im.load()

print("loading: ", time.time() - start)

期望加载时间: <50ms, 实际加载时间: ~150ms


你能避免使用JPEG格式吗?无损图像可能加载更快。 - DisappointedByUnaccountableMod
你有多少这样的图像?它们在磁盘上占用多少字节?它们的宽度和高度是多少? - Mark Setchell
我正在使用手机相机进行拍摄,图像大小为4032 x 3024 - 1.9MB。虽然相机的性能超出了任务要求,但这是我唯一拥有的相机。图像的默认格式为JPEG,并且在任何时候,我的硬盘上可能不会保存超过5个图像,因为在运行代码后它们变得无关紧要。 - Fractal Salamander
1个回答

26

更新的答案

自从我写下这个答案以来,John Cupitt(pyvips的作者)已经提出了一些改进和修正,还有更公平的代码和时间,并且很友好地在这里分享了他们。请查看他改进的版本,与我的代码并列或者甚至更优先。

原始答案

JPEG库有一个"加载时缩小"的功能,可以避免大量的I/O和解压缩。您可以使用PIL/Pillow的Image.draft()函数来利用这一功能,所以不必像这样读取完整的4032x3024像素:

from PIL import Image

im = Image.open('image.jpg')
px = im.load() 

在我的Mac上,这需要297毫秒,你可以执行以下操作并读取1008x756像素,即宽度的1/4和高度的1/4。
im = Image.open('image.jpg') 
im.draft('RGB',(1008,756)) 
px = im.load()

只需要75毫秒,即快了4倍。
为了好玩,我尝试了以下各种技术的比较:
#!/usr/bin/env python3 

import numpy as np 
import pyvips 
import cv2 
from PIL import Image 

def usingPIL(f): 
    im = Image.open(f) 
    return np.asarray(im) 

def usingOpenCV(f): 
    arr = cv2.imread(f,cv2.IMREAD_UNCHANGED) 
    return arr 

def usingVIPS(f): 
    image = pyvips.Image.new_from_file(f, access="sequential") 
    return imgnp.numpy() 

def usingPILandShrink(f): 
    im = Image.open(f)  
    im.draft('RGB',(1008,756))  
    return np.asarray(im) 

def usingVIPSandShrink(f): 
    image = pyvips.Image.new_from_file(f, access="sequential", shrink=4) 
    return imgnp.numpy() 

然后将其加载到ipython中,并进行了如下测试:
%timeit usingPIL('image.jpg')
315 ms ± 8.76 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit usingOpenCV('image.jpg')
102 ms ± 1.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit usingVIPS('image.jpg')
69.1 ms ± 31.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit usingPILandShrink('image.jpg')
77.2 ms ± 994 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit usingVIPSandShrink('image.jpg')                                                    
42.9 ms ± 332 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

看起来pyVIPS在这里是明显的赢家!
关键词:Python,PIL,Pillow,图像,图像处理,JPEG,加载时缩小,草稿模式,读取性能,加速。

@jcupitt 您说得完全正确 - 我的OpenCV使用libjpeg-turbo。我使用了这个方便的答案进行检查 https://stackoverflow.com/a/59281440/2836621 不确定如何在OpenCV中禁用它,或者如何在PIL和pyvips中启用它以使其更公平? - Mark Setchell
那些vips的结果看起来可疑;在一张大图像上比PIL快300倍?我在我的一个项目中尝试了vips,实际上比PIL慢几倍... - marcelm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接