Benchmark of Python Image Processing(resize)

下記記事で、 Imlib2 スゲーよってことで、 Pythonでもベンチマークいるのではないかと思いベンチマークをとってみました。

Imlib2でImageMagickより3倍高速かつ美しいサムネイル画像の生成 - 床のトルストイ、ゲイとするとのこと

対象のモジュールは以下です。

結果としては、PythonでもImlib2速いねってことです、はい。 OpenCVが以外に頑張っています。

http://image.hexacosa.net/images/container/00000000000003f2.png

出力画像

オリジナルの画像は以下のものを使用しました。

http://upload.wikimedia.org/wikipedia/commons/d/df/SAND_LUE.jpg

pgmagickやPythonMagickのsharpenメソッドを使う以外は、 特に大差無いのではないかと思っています。 gdモジュールではカラー画像にできませんでした。 特に使うことも無いと思うので、深追いはしていません。

左(上)から、gd、imlib2、PythonMagick、PythonMagick(+sharpen)、pgmagick、pgmagick(+sharpen)、 OpenCVの画像です。

http://www.hexacosa.net/static/smallimage/outgd.jpg http://www.hexacosa.net/static/smallimage/outimlib2.jpg http://www.hexacosa.net/static/smallimage/outpil.jpg http://www.hexacosa.net/static/smallimage/outim.jpg http://www.hexacosa.net/static/smallimage/outimsharpen.jpg http://www.hexacosa.net/static/smallimage/outpg.jpg http://www.hexacosa.net/static/smallimage/outpgsharpen.jpg http://www.hexacosa.net/static/smallimage/outcv.jpg http://www.hexacosa.net/static/mediumimage/outgd.jpg http://www.hexacosa.net/static/mediumimage/outimlib2.jpg http://www.hexacosa.net/static/mediumimage/outpil.jpg http://www.hexacosa.net/static/mediumimage/outim.jpg http://www.hexacosa.net/static/mediumimage/outimsharpen.jpg http://www.hexacosa.net/static/mediumimage/outpg.jpg http://www.hexacosa.net/static/mediumimage/outpgsharpen.jpg http://www.hexacosa.net/static/mediumimage/outcv.jpg

ファイルサイズ

それぞれの画像のファイルサイズは以下になります。(単位はbyteです)

module/size Small Medium Large
gd 18816 150404 488661
imlib2 7892 60862 196425
PIL 16826 137216 454370
PythonMagick 43649 156019 451105
PythonMagick(sharpen) 45894 177725 523396
pgmagick 38747 181871 541675
pgmagick(sharpen) 43016 214858 636885
OpenCV 16428 133913 439178

ベンチマークスクリプト

4288x2848の画像を180x120、600x400、1200x800にリサイズします。 それぞれ10回ずつの合計値をとっています。JPEGの保存品質(quality)は95にしました。 kaa-imlib2は保存品質を変更できなかったので、値は不明です。

ベンチマーク取得用のスクリプトは以下のような感じです。

from benchmarker import Benchmarker
import Image
#import PythonMagick
import pgmagick
import opencv.cv as cv
import opencv.highgui as highgui
import kaa.imlib2 as imlib2
import gd

N = 10


def gd_scale(filename, width, height):
    im = gd.image(filename)
    newim = gd.image((width, height))
    size = im.size()
    im.copyPaletteTo(newim)
    im.copyResampledTo(newim,
                     (0, 0), (0, 0),
                     (width, height), (size[0], size[1]))
    newim.writeJpeg('outgd.jpg', 95)


def imlib2_scale(filename, width, height):
    im = imlib2.Image(filename)
    newim = im.scale((width, height))
    newim.save('outimlib2.jpg')


def pil_scale(filename, width, height):
    im = Image.open(filename)
    newim = im.resize((width, height), Image.ANTIALIAS)
    newim.save('outpil.jpg', quality=95)


def imagemagick_scale_plus_sharpen(filename, width, height):
    im = PythonMagick.Image(filename)
    im.scale('%dx%d' % (width, height))
    im.sharpen(1)
    im.quality(95)
    im.write('outimsharpen.jpg')


def imagemagick_scale(filename, width, height):
    im = PythonMagick.Image(filename)
    im.quality(95)
    im.scale('%dx%d' % (width, height))
    im.write('outim.jpg')


def pgmagick_scale_plus_sharpen(filename, width, height):
    im = pgmagick.Image(filename)
    im.scale('%dx%d' % (width, height))
    im.sharpen(1)
    im.quality(95)
    im.write('outpgsharpen.jpg')


def pgmagick_scale(filename, width, height):
    im = pgmagick.Image(filename)
    im.scale('%dx%d' % (width, height))
    im.quality(95)
    im.write('outpg.jpg')


def opencv_scale(filename, width, height):
    im = highgui.cvLoadImage(filename)
    newim = cv.cvCreateImage(cv.cvSize(width, height), 8, 3)
    cv.cvResize(im, newim, cv.CV_INTER_AREA)
    highgui.cvSaveImage("outcv.jpg", newim)


def exebench(width):
    """
    benchorg.jpg is
    'http://upload.wikimedia.org/wikipedia/commons/d/df/SAND_LUE.jpg'
    """
    bm = Benchmarker(30)
    height = width * 2 / 3
    with bm("gd"):
        for i in range(N):
            gd_scale('benchorg.jpg', width, height)
    with bm("imlib2"):
        for i in range(N):
            imlib2_scale('benchorg.jpg', width, height)
    with bm("PIL"):
        for i in range(N):
            pil_scale('benchorg.jpg', width, height)
    #with bm("PythonMagick"):
    #    for i in range(N):
    #        imagemagick_scale('benchorg.jpg', width, height)
    #with bm("PythonMagick(+sharpen)"):
    #    for i in range(N):
    #        imagemagick_scale_plus_sharpen('benchorg.jpg', width, height)
    with bm("pgmagick"):
        for i in range(N):
            pgmagick_scale('benchorg.jpg', width, height)
    with bm("pgmagick(+sharpen)"):
        for i in range(N):
            pgmagick_scale_plus_sharpen('benchorg.jpg', width, height)
    with bm("opencv"):
        for i in range(N):
            opencv_scale('benchorg.jpg', width, height)
    bm.print_compared_matrix()

if __name__ == '__main__':
    exebench(180)
    print "=" * 70
    exebench(600)
    print "=" * 70
    exebench(1200)

PythonMagickとpgmagickは同時に使用できないので、別々に実行しました。

以下にスクリプトと結果を置いているので細かい結果とかを知りたければ 見てみてください。

http://www.hexacosa.net/hgrepos/python-snipets/file/bf1b91ed1a38/imageprocessing

まとめ

小さい画像だとあまり画質に差がでませんので、 Imlib2の使用を検討してもよいのではないかと思います。 私は大きな画像になるとImageMagickまたはGraphicsMagickの sharpenフィルターを使った画像の方が好みなので、 pgmagickを使用することにします。 この辺は用途に合わせて選んだ方が良さそうです。