まえおき
Adobe によれば、ポスタリゼーションは「色の数を少なくし、繊細なグラデーションを大まかな色合いにすることで、絵の具を塗ったような、またはエアブラシを使ったような効果」を得る画像処理の技法のひとつです。
Adobe 製品ならアーティスティックな効果も思いのままでしょうが、フリーでやりたくなるのが人情というものです。そこで、Python+Pillow を試します。
ImageOps.posterize
PillowにはImageOps.posterize
という、そのまんまの名称の関数があります。次の関数シグニチャ(👉リファレンス)からわかるように、有効なビット数を指定することで減色します。このビット数は全カラーチャネルに等しく適用されます。
PIL.ImageOps.posterize(image: Image, bits: int) → Image
この関数でたとえばbits=3
を指定すると、RGB のそれぞれの色のバリエーションが23=8になるので、8×8×8=512色に減色されます。もとの1600万余の色数に比べれば格段に減っていますが、意外ともとの色合いは保たれるもので、ポスタリゼーションした気分にはなりません。
>>> from PIL import Image, ImageOps
>>> rgb = Image.open('pexels-pixabay-279360.jpg')
>>> ImageOps.posterize(rgb, 3).save('rgb-b3.png')
サンプルの猫画像はPexelsのものを利用させてもらいました。
ビット数単位なので、これより減色させるとなると、bits=2
(64色)かbits=1
(8色)しかチョイスはありません。
ポスタリゼーションというより、ブラウン管テレビの狂った色調みたいです(昭和ネタですみません)。
Image.quantization
色数が少ないといえば GIF で、Pillow には RGB を GIF のカラーパレットに変換するImage.quantize
という関数もあります。次の関数シグニチャ(👉リファレンス)からわかるように、colors
から色数を1~256の間で指定できます。
Image.quantize(colors: int = 256, method: int | None = None, kmeans: int = 0,
palette=None, dither: Dither = Dither.FLOYDSTEINBERG) → Image
先ほどロードしたrgb
で、32色と4色を試してみます。
>>> rgb.quantize(colors=32).save('gif-c32.png')
>>> rgb.quantize(colors=4).save('gif-c4.png')
ややモノトーンですが、悪くはないですね。
HSV経由
色の塩梅を調整するなら、RGB より HSV のほうがよい結果が出やすいのは周知のとおりです。しかし、残念ながら、ImageOps.posterize
は HSV には対応していません。元画像をImage.convert
から HSV に変換して試します。
>>> hsv = rgb.convert('HSV') # RGB画像をHSVに変換
>>> hsv.mode # モードの確認
'HSV'
>>> ImageOps.posterize(hsv, bits=2)
︙
OSError: not supported for mode HSV
そこで、HSV 画像をImage.split
でチャネル単位に分解し、それぞれをモノクロ画像としてImageOps.posterize
をかけ(モノクロ画像の L モードはサポートされている)、Image.merge
でまたもとのHSVに戻すという迂路を使います。あと、保存する前にもとの RGB に戻します。
H(色相)、S(彩度)、V(明るさ)のすべてについて2ビットに減色します。
>>> h_s_v = hsv.split()
>>> Image.merge('HSV', [ImageOps.posterize(c, 2) for c in h_s_v]).convert('RGB').save('hsv-b2.png')
ポスターというのものはもともと色鮮やかで、明るいものです。そこで、強制的に彩度と輝度を最大値(255)にリセットしてみます。今度は色相は4ビット(16色)にしました。
>>> p255 = Image.new('L', hsv.size, color=255)
>>> Image.merge('HSV', [ImageOps.posterize(h_s_v[0], 4), p255, p255]).convert('RGB').save('hsv-b4-255.png')
ポスターのように色が限られたのは確かですが、ここまでやるともとの絵柄がなんだかわかりません。どちらかというとセグメンテーションみたいで、やりすぎな気配が濃厚です。
おわりに
と、まぁ、いろいろなポスタリゼーションを試してみました。方法と各種のパラメータを組み合わせれば、少しは狙った効果が得られるのではないかと思います。
Pillow/PIL はかなり使い込んだつもりでいましたが、ImageOps.posterize
が HSV や P(GIF)をサポートしていないのは今日まで知りませんでした(マニュアルには明記されていない)。まだまだ修行が足りないようです。2年前(2022年9月)に書いた Pillow/PIL の教本でも、ポスタリゼーションは取り上げても、ImageOps.posterize
の制約にまでは手が及んでいませんでした。ここで、追記させてもらった次第です。
ご購入はこちらから【出版社 | ヨドバシカメラ | 楽天ブックス | amazon.co.jp】。