単一のスレッドで PIL トリミングよりもはるかに高速になることはありませんが、複数のコアを使用してすべてを高速化できます! :)
以下のコードを 8 コアの i7 マシンと、7 歳の 2 コアでかろうじて 2 GHz のラップトップで実行しました。両方とも実行時間が大幅に改善されました。ご想像のとおり、改善は利用可能なコアの数に依存していました。
コードのコアは同じです。関数を値のリストに並列に適用できるように、ループを実際の計算から分離しただけです。
したがって、この:
for i in range(0,num_images):
t = time.time()
im = Image.open('%03i.png'%i)
w,h = im.size
imc = im.crop((w-50,h-50,w+50,h+50))
print 'Time to open: %.4f seconds'%(time.time()-t)
#convert them to numpy arrays
data = np.array(imc)
なりました:
def convert(filename):
im = Image.open(filename)
w,h = im.size
imc = im.crop((w-50,h-50,w+50,h+50))
return numpy.array(imc)
高速化の鍵はライブラリのPool
機能です。multiprocessing
複数のプロセッサ間で物事を実行するのは簡単です。
完全なコード:
import os
import time
import numpy
from PIL import Image
from multiprocessing import Pool
# Path to where my test images are stored
img_folder = os.path.join(os.getcwd(), 'test_images')
# Collects all of the filenames for the images
# I want to process
images = [os.path.join(img_folder,f)
for f in os.listdir(img_folder)
if '.jpeg' in f]
# Your code, but wrapped up in a function
def convert(filename):
im = Image.open(filename)
w,h = im.size
imc = im.crop((w-50,h-50,w+50,h+50))
return numpy.array(imc)
def main():
# This is the hero of the code. It creates pool of
# worker processes across which you can "map" a function
pool = Pool()
t = time.time()
# We run it normally (single core) first
np_arrays = map(convert, images)
print 'Time to open %i images in single thread: %.4f seconds'%(len(images), time.time()-t)
t = time.time()
# now we run the same thing, but this time leveraging the worker pool.
np_arrays = pool.map(convert, images)
print 'Time to open %i images with multiple threads: %.4f seconds'%(len(images), time.time()-t)
if __name__ == '__main__':
main()
かなり基本的です。ほんの数行の追加コードと、変換ビットを独自の関数に移動するための少しのリファクタリングのみです。結果が物語っています。
結果:
8 コア i7
Time to open 858 images in single thread: 6.0040 seconds
Time to open 858 images with multiple threads: 1.4800 seconds
2 コア Intel Duo
Time to open 858 images in single thread: 8.7640 seconds
Time to open 858 images with multiple threads: 4.6440 seconds
では、どうぞ!非常に古い 2 コア マシンを使用している場合でも、画像を開いて処理するのに費やす時間を半分にすることができます。
注意事項
メモリー。数千枚の画像を処理している場合、おそらくある時点で Python のメモリ制限を超えてしまうでしょう。これを回避するには、データをチャンクで処理するだけです。マルチプロセッシングの優れた点はすべて活用できますが、ほんの少しずつです。何かのようなもの:
for i in range(0, len(images), chunk_size):
results = pool.map(convert, images[i : i+chunk_size])
# rest of code.