PythonのPillowのImage.effect_mandelbrotの使い方: マンデルブロ集合を描く

63, 2020-09-30

目次

Image.effect_mandelbrotの使い方

Pythonの画像処理ライブラリであるPillowには画像を処理するImageモジュールがあります。
Imageモジュールはマンデルブロ集合の画像を生成する関数effect_mandelbrot()を持っています。

この関数を使うと簡単にマンデルブロ集合を描くことが出来ます。

マンデルブロ集合とは?

数学(特に複素力学系)で提唱された集合のことです。
数学者ブノワ・マンデルブロにちなんでこの名が付けられました。
高解像度のマンデルブロ集合の描写は、マシンパワーを必要とすることから、パソコンのベンチマークでも使われることがあるそうです。

Image.effect_mandelbrotの構造

Image.effect_mandelbrot()は↓のような構造を持っています。

PIL.Image.effect_mandelbrot(size, extent, quality)

size

第1引数のsizeは生成する画像のサイズのタプルです。
タプルの第1要素は横幅、第2要素は高さを指定します。
たとえば(width, height)のようにです。

extent

マンデルブロ集合を生成する範囲をタプルで指定します。
言い換えるとマンデルブロ集合のキャンバス上の大きさです。
タプルは第1要素が第1のx座標、第2要素が第1のy座標、第3要素が第2のx座標、第4要素が第2のy座標になります。
これは(x0, y0, x1, y1)と表すことが出来ます。
ここに指定する値はいわゆるピクセルではありません。ですので、sizeと似たような値を指定してもうまく画像が生成されないので注意が必要です。

quality

生成するマンデルブロ集合のクオリティです。
2100の範囲で指定します。
値が低いほど抽象的なマンデルブロ集合が生成されます。
値が100に近ければいわゆるネット上でよく見る高解像度なマンデルブロ集合が生成されます。

戻り値

戻り値はImageオブジェクトです。

高クオリティなマンデルブロ集合を描く

クオリティ100のマンデルブロ集合を描いてみます。
画像のサイズは横幅512px, 高さ512pxです。

from PIL import Image

# マンデルブロ集合のパラメーター
size = (512, 512)  # (width, height)
extent = (-3, -2, 2, 2)  # (x1, y1, x2, y2)
quality = 100  # 2 ~ 100

# マンデルブロ集合を生成
im = Image.effect_mandelbrot(size, extent, quality)

# 画像を保存
im.save('dst/out0.png')

出力結果。

【0063】out0.png

いわゆるよく見かけるマンデルブロ集合が生成されました。

簡単だな~

高クオリティなマンデルブロ集合を拡大する

extentの値を工夫するとマンデルブロ集合を拡大することができます。
↓のようにextent(-1, -1, 0.0001, 0.0001)を指定します。
その他の値は変わりません。

from PIL import Image

# マンデルブロ集合のパラメーター
size = (512, 512)  # (width, height)
extent = (-1, -1, 0.0001, 0.0001)  # (x1, y1, x2, y2)
quality = 100  # 2 ~ 100

# マンデルブロ集合を生成
im = Image.effect_mandelbrot(size, extent, quality)

# 画像を保存
im.save('dst/out1.png')

出力結果。

【0063】out1.png

低クオリティなマンデルブロ集合を描く

qualityの値を低くすると、描かれるマンデルブロ集合が抽象的になっていきます。
たとえばquality20にすると、↓のような出力になります。

【0063】out2.png

quality8まで下げるともはや原型をとどめません。

【0063】out3.png

イラストとマンデルブロ集合を合成する

【共有】水没する2人

このイラストとマンデルブロ集合を合成してみたいと思います。

from PIL import Image

# イラストを読み込む
illust = Image.open('img/a.png').convert('RGB')
ir, ig, ib = illust.split()  # バンドを抽出

# マンデルブロ集合のパラメーター
size = (500, 500)  # (width, height)
extent = (-1, -1, 0.0001, 0.0001)  # (x1, y1, x2, y2)
quality = 20  # 2 ~ 100

# マンデルブロ集合を生成
mandebrot = Image.effect_mandelbrot(size, extent, quality)
mandebrot = mandebrot.convert('RGB')
mr, mg, mb = mandebrot.split()  # バンドを抽出

# イラストとマンデルブロ集合のバンドを合成する
im = Image.merge('RGB', (ir, mg, mb))

# 画像を保存
im.save('dst/out4.png')

出力結果。

【0063】out4.png

マンデルブロ集合の規則的な描写は人工物よりは自然物の方が合成したときに合うかもしれないですね。

まぁ好みによる

ソースコードの分析

Pillowのマンデルブロ集合を描く関数は最終的にC言語で描かれたモジュールに辿り着きます。

速度を確保するためにPythonのモジュールをCで書くというのはよくあることです。

関数を見てみると非常にシンプルなものだというのがわかります。
自力でマンデルブロ集合を描いてみたい方は参考にされてみてはどうでしょうか。

問題

Q1: マンデルブロ集合は何の分野の集合か答えよ

Q1: 哲学
Q2: 数学
Q3: 物理学

Q2: Image.effect_mandelbrot()の第1引数の説明として適当なものを答えよ

Q1: 画像のモード
Q2: 画像のサイズ
Q3: マンデルブロ集合のサイズ

Q3: Image.effect_mandelbrot()の戻り値として適当なものを答えよ

Q1: Image
Q2: int
Q3: dict


正解はこちら↓

Q1: 2
Q2: 2
Q3: 1