2

Python で実現した私の最初のプロジェクトの 1 つは、スティック パーコレーションのモンテカルロ シミュレーションを行います。コードは継続的に成長しました。最初の部分は、スティック浸透の視覚化でした。width*length の領域に、特定の長さの定義された密度 (スティック/領域) の直線スティックが、ランダムな開始座標と方向でプロットされます。私は gnuplot をよく使うので、生成された (x, y) の開始座標と終了座標をテキスト ファイルに書き込んで、後で gnuplot にしました。

次に、scipy.ndimage.measurements を使用して画像データを分析する良い方法を見つけましたイメージは、グレースケールで ndimage.imread を使用して読み取られます。結果のnumpy配列は、異なるスティック間の接続にのみ関心があるため、ブール値にさらに縮小されます。結果のクラスターは、ndimage.measurements で分析されます。これにより、一方から他方につながる経路があるかどうかを調べることができます。最小化された例はこちらです。

import random
import math
from scipy.ndimage import measurements
from scipy.ndimage import imread
import numpy as np
import matplotlib.pyplot as plt

#dimensions of plot
width = 10
length = 8
stick_length = 1
fig = plt.figure(frameon=False)
ax = fig.add_axes([0, 0, 1, 1])
fig.set_figwidth(width)
fig.set_figheight(length)
ax.axis('off')

file = open("coordinates.txt", "w")

for i in range (300):
    # randomly create (x,y) start coordinates in channel and direction
    xstart = width * random.random()        # xstart = 18
    ystart = length * random.random()        # ystart = 2
    # randomly generate direction of stick from start coordinates and convert from GRAD in RAD
    dirgrad = 360 * random.random()
    dirrad = math.radians(dirgrad)
    # calculate (x,y) end coordinates
    xend = xstart + (math.cos(dirrad) * stick_length)
    yend = ystart + (math.sin(dirrad) * stick_length)
    # write start and end coordinates into text file for gnuplot plotting
    file.write(str(i) + ":\t" + str(xstart) + "\t" + str(ystart) + "\t" + str(dirgrad) + ":\t" + str(xend) + "\t" + str(yend) + "\n")
    file.write(str(i) + ":\t" + str(xend) + "\t" + str(yend) + "\n\n")
    # or plot directly with matplotlib
    ax.plot([xstart,xend],[ystart,yend],"black", lw=1)
fig.savefig("testimage.png", dpi=100)

# now read just saved image and do analysis with scipy.ndimage
fig1, ax1 = plt.subplots(1,1)
img_input = imread("testimage.png", flatten = True) # read image to np.ndarray in grey scales
img_bw = img_input < 255 # convert grey scales to b/w (boolean)
labeled_array, num_clusters = measurements.label(img_bw) #labeled_array: labeled clusters in array, num_clusters: number of clusters
area = measurements.sum(img_bw, labeled_array, index=np.arange(labeled_array.max() + 1)) # area of each cluster
areaImg = area[labeled_array] # label each cluster with labelnumber=area
cax = ax1.imshow(areaImg, origin='upper', interpolation='nearest', cmap = 'rainbow')
cbar = fig1.colorbar(cax)
fig1.savefig("testimage_analyzed.png")

これは基本的にうまくいきますが、より多くの異なるスティック密度に対して 1000 回の反復を行う細かいモンテカルロ シミュレーションは、8 時間以上実行されることになります。これは、作成された画像と配列が非常に大きく、何千ものスティックがより高い密度でプロットされているという事実によるものです。その理由は、ピクセル化によるエラーを最小限に抑えながら、さまざまなジオメトリ (たとえば、500 ~ 20000 ピクセルの長さ) をシミュレートしたいからです。

画像データを使用せずにベクトル問題として扱うのが最善の方法だと思いますが、アルゴリズムを開始する方法さえわかりません。また、多くの接続により、データ配列が大きくなる可能性もあります。

上記の方法にとどまると、ファイルにデータを書き込んで再読み込みすることはあまり効果的でないことは明らかです。したがって、これを高速化する方法を探しています。最初のステップとして、matplotlib を使用して画像を作成しましたが、少なくとも各スティックを個別のプロット呼び出しでプロットする場合、スティックの数が多いと最大 10 倍遅くなります。配列内にスティック座標のリストを作成し、1 回のプロット呼び出しで完全なリストをプロットすると、速度が向上する可能性がありますが、画像の書き込みと読み取りのボトルネックが残ります。

スティックの白黒画像を表すブール型のnumpy配列を直接生成する効果的な方法を教えてください。たぶん、座標のリストをプロットし、何らかの方法で図を配列に変換しますか? また、線が PIL 画像にプロットされる興味深い議論も見つけました。これは matplotlib よりも高速でしょうか?

4

1 に答える 1

2

配列内に線分を描画することは、グラフィックス ライブラリの基本的な機能です。最も単純な方法は、おそらくBresenham のアルゴリズムです。高速な言語で実装すると、アルゴリズムは単純で高速になります。純粋な python で実装することはお勧めしません。このアルゴリズムの最も単純なバージョンの欠点は、アンチエイリアス処理されていないことです。線は「ギザギザ」を示しています。より優れたアンチエイリアシングを備えたより高度な方法については、「線画アルゴリズム」を検索してください。

私のeyediagram パッケージは Bresenham のアルゴリズムの Cython 実装があります。この関数は、(x0, y0) から (x1, y1) までの直線に沿って、入力配列の値をインクリメントします。配列の値を 1 に設定するだけの変更は、そのコードにとって些細な変更です。bres_segment_count

例えば、

In [21]: dim = 250

In [22]: num_sticks = 300

の各行にsticksは、「棒」の終点 [x0, y0, x1, y1]が含まれます。

In [23]: sticks = np.random.randint(0, dim, size=(num_sticks, 4)).astype(np.int32)

In [24]: img = np.zeros((dim, dim), dtype=np.int32)

bres_segments_countBresenham のアルゴリズムを使用して各スティックを描画します。線の値を単純に 1 に設定するのではなく、線にimg沿った値がインクリメントされることに注意してください。

In [25]: from eyediagram._brescount import bres_segments_count

In [26]: bres_segments_count(sticks, img)

In [27]: plt.imshow(img, interpolation='nearest', cmap=cm.hot)
Out[27]: <matplotlib.image.AxesImage at 0x10f94b110>

生成されるプロットは次のとおりです。

スティックプロット

于 2015-11-01T23:28:47.907 に答える