Benchmark of Python Image Processing(resize)

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

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

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

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

image

出力画像

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

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

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

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

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

ファイルサイズ

それぞれの画像のファイルサイズは以下になります。(単位は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を使用することにします。 この辺は用途に合わせて選んだ方が良さそうです。