wand/imagemagickは処理が遅いことがあるのでPILで済む処理ならPILがお勧め
色々なサイトで、python2|3での 画像処理の実装として、ImageMagick/wandをおすすめしてるが、実はやや処理が遅い。
GitHub - emcconville/wand: The ctypes-based simple ImageMagick binding for Python
小生の場合、連続して画像処理をさせているスクリプトがあり、straceしてたまたま気づいたのだが結構怪しい処理を色々やってる。
wandとPILで処理時間を比較してみる。
中央にポツンと小さい模様があるだけの 4000バイト以下のモノクロ画像 test.pngを使った例をあげる。増色&減色をするだけの簡単な実装である。
画像の詳細は本件の本質にはあまり影響しないため割愛する。
wandの実装例は次の通り。
import wand
import wand.image
aa = wand.image.Image(filename="test.png")
aa.type = "truecolor"
aa.type = "palette"
#aa.auto_level()
PIL/pillow の実装例は次の通り。
Pillow (PIL Fork) 9.2.0 documentation
import PIL.Image
aa = PIL.Image.open("test.png")
aa.convert("RGBA")
aa.convert("P")
#aa.auto_level()
これを小生の約7000bogomipsの環境で実行するとこうなる。
$ time python3 p.py
real 0m0.073s
user 0m0.059s
sys 0m0.014s
$ time python3 w.py
real 0m0.454s
user 0m0.440s
sys 0m0.099s
PIL版の0.07秒は十分納得できる数字だが、wand版の0.4秒が明らかに遅いことがわかるだろう。
wandで0.4秒掛かってる理由
紆余曲折あったが、理由はわかった。
Imagemagickのライブラリを探すために複雑な処理をしているためだ。
ctypes.util.find_libraryが曲者なのだが、実は内部でgccを実行して、ライブラリのpathを探そうとしてる。
これは imagemagickの方も問題で、非標準なディレクトリへのインストールも提唱してるためだ。
Set the MAGICK_HOME environment variable to the path where you extracted the ImageMagick files. For example:
$ export MAGICK_HOME="$HOME/ImageMagick-7.1.0"
wand側でもこのあたりの言及はしている。
PIL(pillow)+α で行こう
手っ取り早く、PILで行くことにした。
前述の通り、減色程度ならPILで容易に代替可能である。
また代表的な画像処理であろう crop および resize==transform も類似の機能があるため、概ねPILで実装可能である。
小生の運用では、さらにこれに明度レベル調整が必要だった。 wandでは非常に簡単に使える機能なので、このためにwandを使うのなくはない。
auto_levelはPILには機能がないため、自作する必要がある。が、これはすぐ見つかる。例えば次のリンクでは numpy+cv2を使って自分で計算する。
image - Doing the same as ImageMagick's "-level" in python / PIL? - Stack Overflow
wand/imagemagickを辞めて。PILに加えてopencv+numpyまで使うなら本末転倒では?と思う方も居るだろう。 が、小生の場合では、それでもwandより何割か処理が早いことを確認した。そのため、wandを廃止してPIL+opencv/numpyに切り替えた。
Discussion