python/Pillowで輪郭を見つけたり強調したり

しばらく前にOpenCVで輪郭検出をやりましたが、それに近いことがPillowで出来るらしいのでやってみました。 OpenCVと比べると簡単に出来ることは多いけれど、その分細かい調整は出来ない、そんな感じみたいです。

例によって、こちらのレナさんの画像に手を加えてゆきます。

恒例のレナさん

まずは最もシンプルな輪郭検出。

from PIL import Image, ImageFilter

img = Image.open('lena.jpg')
filtered = img.filter(ImageFilter.FIND_EDGES)
filtered.save('edges.jpg')

こんな感じ。 出力は以下のようになります。

黒地に白い線でレナさん

CONTOURを使うと、FIND_EDGESで得られる画像を白黒反転させたような画像を得られます。

img.filter(ImageFilter.CONTOUR).save('contour.jpg')

だいぶ書き方を省略しましたが、基本的にはなにも変わってません。 filterの引数が変わっただけですね。 出力は以下のような感じに。

輪郭を白地に黒い線で書いたレナさん

更に、輪郭強調も出来ます。 シンプルな方法は以下の二通り。

img.filter(ImageFilter.EDGE_ENHANCE).save('enhance.jpg')
img.filter(ImageFilter.EDGE_ENHANCE_MORE).save('enhance_more.jpg')

上が弱め、下が強め。そのまんまですね。 細かい調整はどうも出来ないっぽいです。 出力はこんな感じ。

弱い輪郭強調を掛けたレナさん 強い輪郭強調を掛けたレナさん

一枚目が弱い方、二枚目が強い方です。 不自然に輪郭が際立ってしまった感じ。そしてノイズを拾いまくり。

ある程度ナチュラルに強調してくれるSHAPENってやつがあります。

img.filter(ImageFIlter.SHAPEN).save('shapen.jpg')

なんというか、お察しの通りな書き方? 出力はこんな感じ。

シャープ化したレナさん

ちょっともの足りない感じがします。

SHAPENは自分でパラメータを決めることが出来るようで、以下のような書き方をします。

img.filter(ImageFilter.UnsharpMask(radius=10, percent=200, threshold=5)).save('unsharp.jpg')

画像編集ソフトで見掛けるアンシャープマスク、ってやつですね。 分かりやすくするためにパラメータは適当に強めのものを設定してあります。 このパラメータで実行すると出力は以下のような感じ。

アンシャープマスクで輪郭を強烈に強調したレナさん

かなり強烈です。強烈ですが、そこまで違和感は無いと思います。良い感じ。

他にもよく分からないフィルターが色々あって楽しいので、一度リファレンスをご覧になることをおすすめします。 もうちょいパラメータいじれたらもっと楽しいんでしょうけれど、手軽さの代償ですかねぇ。


参考: