やること
見る方向によって変わる立体アートを作ってみたいです。こういうやつです↓。
アルゴリズムさえ分かれば機械的に設計できますので、挑戦してみましょう。
実行環境
WinPython3.6をおすすめしています。
WinPython - Browse /WinPython_3.6/3.6.7.0 at SourceForge.net
Portable Scientific Python 2/3 32/64bit Distribution for Windows
Google Colaboratoryが利用可能です。
Google Colab
素材
「V」「&」「C」の3文字を用意しました。41*41pxサイズのグレースケール画像です。
pip, import
必要なパッケージをインポートします。足りないと怒られたらpip installしてください。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from PIL import Image
素材の読み込みと表示
素材を2枚指定して読み込みます。
- 2枚の素材を白黒(bool)画像として読み込む
- 画像のサイズを取得して「size」に格納する
- 画像を表示する関数で表示する
#=======================
# パラメータ
#=======================
#画像パス
img_path_x = '14-11_v.png'
img_path_y = '14-11_and.png'
#=======================
# 表示関数
#=======================
def show_bool(img):
plt.imshow(img, vmin = 0, vmax = 1)
plt.show()
plt.close()
#=======================
# 2枚の画像の読み込み
#=======================
#画像の読み込みと二値化
img_x = Image.open(img_path_x).convert('1'); img_x.close
img_y = Image.open(img_path_y).convert('1'); img_y.close
img_x = np.array(img_x)
img_y = np.array(img_y)
#サイズ取得
size = img_x.shape[0]
print('size:{}\n'.format(size))
#表示
show_bool(img_x)
show_bool(img_y)
size:41
「img_x」「img_y」はbool配列ですが、Pythonは親切な言語ですので、最小値 False(=0)を黄色、最大値 True(=1)を紫として表示してくれてます。
アートの作成
アルゴリズムはシンプルで、41*41*41サイズの立方体を用意して、x方向からは「V」の白い部分を削り込み、y方向からは「&」の白い部分を削り込みます。
なお、3Dグラフの表示には少し慣れが必要です。360度グルグル回転させながら表示するようにしています。
#=======================
# アートの作成
#=======================
#1埋めした3次元配列
data = np.ones((size, size, size), dtype=bool)
#1枚目の画像の白部分をx方向から削り込む
for i in range(size):
data[:, i, :] *= np.rot90(img_x==False, -1) #ちょっと回したほうが見やすい
#2枚目の画像の白部分をy方向から削り込む
for i in range(size):
data[i, :, :] *= np.rot90(img_y==False, -1) #ちょっと回したほうが見やすい
for i in range(0, 360):
#表示
fig = plt.figure(figsize=(6, 6))
ax = Axes3D(fig)
#要素に分解してプロット
x, y, z = np.where(data==True)[:3]
ax.plot(x, y, z, 'sk', markersize=5)
#その他の設定
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.set_xlim(0, size)
ax.set_ylim(0, size)
ax.set_zlim(0, size)
#視点(垂直、水平)
ax.view_init(0, 135 - i)
#表示
plt.show()
plt.close()
こんな感じの画像がたくさん表示されます。
360枚をgifにするとこうなります。
「C」と「&」の場合
できました。
「V」「&」「C」を3方向から削り込んだ場合
できませんでした。各方向から見るとこうなっています。
3方向からきちんと見える立体は保証されないようです。