12/9(月) 応用科学学会シンポジウムで自動運転に関する講演を担当します☆彡(試乗会もあります!来て!)

17-9. 太さや模様が不均質なチューリング・パターン

やること

部分的に太さが違う、あるいは部分的に模様が違う、そんなチューリング・パターンを作ってみましょう。

必修科目

こちらを履修しておいてください。

実行環境

WinPythonかGoogle Colaboratoryを用います。

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

どうやって部分的に太さを変えるか

17-7では、次のような円形の畳み込みフィルタを用いて、各セルの状態を更新していきました。畳み込んだ結果が0より大きければ1(True)、0以下であれば0(False)となります。

このとき、r1, r2の規模によってパターンの太さが異なることが分かりました。

r1=3, r2=6

r1=10, r2=20

そこで今回は、規模が異なる複数のフィルターを用意しておいて、フィールドのある部分では小さいフィルターを、ある部分では大きいフィルターを、というように使い分けてみます。

フィールドのどの部分で何番目のフィルターを使うかは、次のとおりとします。

中央が太く、両端が細くなるのではないかと想像しています。

ソースコード

場所によって使うフィルターが違うと、前回までのように scipy.signal.convolv2d() でお手軽に畳み込むことができません。泣きながら手動で畳み込むコードを書きました。

import numpy as np
import numpy.random as nr
import matplotlib.pyplot as plt

#============================
#設定
#============================

#フィールドサイズ
h, w = 90, 160

#パラメータ
r1_range = range(3, 11, 1) # 個数は合わせる
r2_range = range(6, 21, 2) # 個数は合わせる

w1 = 10
w2 = -3.2

#終了ステップ数
max_step = 20


#============================
#メイン処理
#============================

#フィールドの初期化
#f = np.zeros((h, w), dtype=bool) #0で初期化
f = nr.randint(0, 2, (h, w), dtype=bool) #ランダムに初期化

#畳み込み用のフィルタを作る関数
def make_filter(r1, r2):
    g = np.zeros((r2*2 - 1, r2*2 - 1))
    for i in range(len(g)):
        for j in range(len(g[0])):
            if (i + 1 - r2)**2 + (j + 1 - r2)**2 < r1**2:
                g[i, j] = w1
            if r1**2 <= (i + 1 - r2)**2 + (j + 1 - r2)**2 < r2**2:
                g[i, j] = w2
    return g

#規模が異なるフィルタを複数作成しておく
g_all = []
for i in range(len(r1_range)):
    g_all.append(make_filter(r1_range[i], r2_range[i]))

print('フィルターの個数:{}'.format(len(g_all)))

#全フィルターの確認
for g in g_all:
    plt.imshow(g, cmap='RdGy', vmin=-15, vmax=15)
    plt.show(), print()

#フィールドの拡張幅
s = r2_range[-1]

#フィールドの各地点でどのフィルタを用いるか
c = np.tile(np.hstack([np.linspace(0, len(g_all), w//2, endpoint=False), np.linspace(0, len(g_all), w//2, endpoint=False)[::-1]]), (h, 1))
#切り捨てて整数に
c = np.array(c, dtype=int)
#表示
plt.imshow(c, cmap='binary')
plt.show(), print()

#初期状態の表示
plt.imshow(f, cmap='binary', vmin=0, vmax=1)
#plt.savefig('save/{}.png'.format(0), bbox_inches='tight', pad_inches=0)
plt.show(), print()

#状態の更新
for n in range(1, max_step + 1):
    #畳み込みとフィールドの更新、0より大きければ生存(True)、0以下であれば死(False)
    #f = signal.convolve2d(f, g, mode='same',boundary='wrap') >= 0
    
    #フィールドを拡張しておく
    f = np.hstack([f[:, -s:], f, f[:, :s]])
    f = np.vstack([f[-s:, :], f, f[:s, :]])
    
    #手動で畳み込む
    f_new = np.zeros((h, w), dtype=bool)
    for i in range(h):
        for j in range(w):
            #この地点でのフィルターの選択
            g = g_all[c[i, j]]
            #フィルターの半径
            g_r = g.shape[0] // 2
            #拡張フィールドにおける座標
            center = (i + s, j + s)
            #拡張フィールドをフィルターサイズに切り取る
            f_cut = f[center[0] - g_r : center[0] + g_r + 1, center[1] - g_r : center[1] + g_r + 1]
            #畳み込み
            f_new[i, j] = np.sum(f_cut * g) >= 0
    
    #フィールドの更新
    f = f_new
    
    #表示
    plt.imshow(f, cmap='binary', vmin=0, vmax=1)
    #plt.savefig('save/{}.png'.format(n), bbox_inches='tight', pad_inches=0)
    plt.show(), print()

結果

フィルターの個数:8

いいんじゃないでしょうか!

どうやって部分的に模様を変えるのか

一方で、斑点になるか線になるかは、w1, w2のバランスによって決まるのでした。

w1=10, w2=-3.5

w1=10, w2=-3.0

w1=10, w2=-2.5

ということで、今度は場所によってw2を変えてみます。

w2_range = np.arange(-4.0, -2.2, 0.1)

という18段階にして、フィールドのどの部分で何番目のフィルターを使うかは、次のとおりとします。(この図、伝わるのか?)

ソースコード

import numpy as np
import numpy.random as nr
import matplotlib.pyplot as plt

#============================
#設定
#============================

#フィールドサイズ
h, w = 90, 160

#パラメータ
r1 = 5
r2 = 10

w1 = 10
w2_range = np.arange(-4.0, -2.2, 0.1)

#終了ステップ数
max_step = 20


#============================
#メイン処理
#============================

#フィールドの初期化
#f = np.zeros((h, w), dtype=bool) #0で初期化
f = nr.randint(0, 2, (h, w), dtype=bool) #ランダムに初期化

#畳み込み用のフィルタを作る関数
def make_filter(w1, w2):
    g = np.zeros((r2*2 - 1, r2*2 - 1))
    for i in range(len(g)):
        for j in range(len(g[0])):
            if (i + 1 - r2)**2 + (j + 1 - r2)**2 < r1**2:
                g[i, j] = w1
            if r1**2 <= (i + 1 - r2)**2 + (j + 1 - r2)**2 < r2**2:
                g[i, j] = w2
    return g

#規模が異なるフィルタを複数作成しておく
g_all = []
for i in range(len(w2_range)):
    g_all.append(make_filter(w1, w2_range[i]))

print('フィルターの個数:{}'.format(len(g_all)))

#フィールドの拡張幅
s = r2

"""
以下同じ
"""

結果

フィルターの個数:18

こちらも良くできています!やりました!

タイトルとURLをコピーしました