0
0

画像のポスタリゼーション

Last updated at Posted at 2024-09-13

まえおき

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')

240913-rgb-b3.png

サンプルの猫画像はPexelsのものを利用させてもらいました。

ビット数単位なので、これより減色させるとなると、bits=2(64色)かbits=1(8色)しかチョイスはありません。

240913-rgb-b2.png 240913-rgb-b1.png

ポスタリゼーションというより、ブラウン管テレビの狂った色調みたいです(昭和ネタですみません)。

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')

240913-gif-c32.png 240913-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')

240913-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')

240913-hsv-b4-255.png

ポスターのように色が限られたのは確かですが、ここまでやるともとの絵柄がなんだかわかりません。どちらかというとセグメンテーションみたいで、やりすぎな気配が濃厚です。

おわりに

と、まぁ、いろいろなポスタリゼーションを試してみました。方法と各種のパラメータを組み合わせれば、少しは狙った効果が得られるのではないかと思います。

Pillow/PIL はかなり使い込んだつもりでいましたが、ImageOps.posterizeが HSV や P(GIF)をサポートしていないのは今日まで知りませんでした(マニュアルには明記されていない)。まだまだ修行が足りないようです。2年前(2022年9月)に書いた Pillow/PIL の教本でも、ポスタリゼーションは取り上げても、ImageOps.posterizeの制約にまでは手が及んでいませんでした。ここで、追記させてもらった次第です。

ご購入はこちらから【出版社 | ヨドバシカメラ | 楽天ブックス | amazon.co.jp】。

表紙

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0