(Pillow.ImageMorph)実用性が乏しそうなものにバグがあると困る話

Python Pillow (PIL) examples の話の続きである。

Python Pillow (PIL) examples も、一般人レベルの日常使いな範囲では結構揃ってきた。リファレンスじゃないしね、てのもあるから、はなから書く気がないものもある。

今問題にしたいのは ImageMorph と PSDraw。後者は EPS (encapsulated postscript) として書き出せないくせに EPS しか読み出せない、という問題がありつつも、措置を例として書けそうなので、まぁ今回は目を瞑るとして。ImageMorph がね、ヒドい。

まずもってして このドキュメント で何かしらでも理解出来る人がいたら天才である。実際にはこんなふうに使う:

 1 from PIL import Image, ImageMorph
 2 from PIL.ImageMorph import LutBuilder, MorphOp
 3 
 4 # original image
 5 img = Image.open("data/binary_shapes_01.jpg")  # grayscale
 6 img.load()  # MorphOp.apply expects image are loaded.
 7 
 8 # make builder by predefined pattern name
 9 # ("dilation4" is actually patterns=['4:(... .0. .1.)->1'])
10 lb = LutBuilder(op_name="dilation4")
11 lut = lb.build_lut()
12 op = MorphOp(lut)
13 _, dimg = op.apply(img)
14 dimg.show()
15 
16 # make builder with custom patterns
17 lb = LutBuilder(patterns=['4:(... .0. .1.)->1'])
18 lut = lb.build_lut()
19 op = MorphOp(lut)
20 _, dimg = op.apply(img)
21 dimg.show()

この使い方がわかるまで、ドキュメントは頼りにならず、PIL/ImageMorph.py のソースコードを読むしかなかった。

問題点の最初は「バグ」に関するものではなくて、そもそもの実用性について。

そもそも ImageMorph ってのは何するものか? ドキュメントからは「provides morphology operations on images.」ということだけが唯一伝わってくる。ソースコードコメントの先頭からは「A binary morphology add-on」だということがわかる。「2014-06-04 Initial version.」の割には wikipedia とか指してくれたり、みたいな親切は一切なくて。うーん、もちっとどうにかなるでしょうに…。マジメに読むとヘビィだが、morphology は これのことである。

「実用性」、とは。 binary であることが問題…というのはむしろ Pillow でない morphology を試してみてよくわかった。マジメに morphology したかったら scikit-image とか使ったほうがもちろんハッピー。どのくらいハッピーかといえば、10億倍くらい。scikit-image を使うならこんな:

 1 import numpy as np
 2 from PIL import Image  # まぁこの場合は Pillow いらんのだけれど
 3 from skimage.morphology import dilation, square
 4 
 5 img = Image.open("data/binary_shapes_01.jpg")
 6 # 正方でないと期待通りに機能しないみたい
 7 img = img.resize((img.width, img.width))
 8 asarr = np.array(img.getdata()).reshape(img.size)
 9 asarr = dilation(asarr, square(5))  # dilation (https://en.wikipedia.org/wiki/Dilation_(morphology))
10 
11 dimg = Image.new("L", img.size)
12 dimg.putdata(asarr.flatten())
13 dimg.show()

dilation のぼやっとした説明としては、「明るい領域を増やし、暗い領域を減らす」。scikit-image のは、binary だけでなく grayscale のもちゃんと処理してくれるので、利用者が期待した通りの結果を得られる。まぁ Pillow 版は実際に自分でやってみればいいと思うよ。間違いなく「うーん、これはワタシには必要ない」ときっと思うはず。

そして。「だって使いにくくね?」。このヘンチクリンなミニ言語を「駆使すべし」って、作り手の気持ちもわからんでもないんだけれど、「010 111 010」が

1 np.array([0, 1, 0], [1, 1, 1], [0, 1, 0])

であるからといって、「あー記述が多くて大変だぁ」なんて誰も思いませんて。

で、まぁ本題というか。#2590。このドキュメントだからねぇ。誰も使おうともしてないんだろう。こんなしょーもないバグが眠っておる。やっぱドキュメントファーストであるべき、てことなのかもなぁ。

最後に。「実用性が乏しそうなものにバグがあると困る」のは、今回のワタシのように、「ひとさま向けにプロジェクトを紹介したい」場合である。そうでないなら忘れてしまえば良いのであるから。

06/25 05:00 追記:
hugovk:

This was likely fixed in #2554, merged 11 days ago but not yet released; it’ll be due out in 4.2.0 at the start of July.

Please could you test the master branch?

アタシの間が悪かったのか、はたまた、マスターブランチの履歴まで追っかけてから issue をあげるべきだったのか。なんともはやタイムリー過ぎた issue になったのであった…。

あと一応 ImageMorph の最小限の例 は書いてみた。scikit-image の例だったら結構楽しい例を作れるんだけれど、Pillow のはこんななのでかなり用途が限られる、と。