2

私は、3D 三角形メッシュを操作するコードに取り組んでいます。メッシュ データをインポートしたら、空間内の同じポイントにある頂点を「統合」する必要があります。

numpy 配列がデータを格納および操作する最速の方法であると想定してきましたが、重複するエントリを追加することを避けながら頂点のリストを作成する高速な方法を見つけることができないようです。

したがって、メソッドをテストするには、10000 の一意の行を持つ 3x30000 配列を作成します。

import numpy as np
points = np.random.random((10000,3))
raw_data = np.concatenate((points,points,points))
np.random.shuffle(raw_data)

これはメッシュ データの適切な近似として機能し、各ポイントはファセット頂点として 3 回表示されます。統一しながら、一意の頂点のリストを作成する必要があります。ポイントがすでにリストにある場合は、そのポイントへの参照を保存する必要があります。

これまでにnumpyを使用して思いついた最高のものは次のとおりです。

def unify(raw_data):
    # first point must be new
    unified_verts = np.zeros((1,3),dtype=np.float64)
    unified_verts[0] = raw_data[0]
    ref_list = [0]

    for i in range(1,len(raw_data)):
        point = raw_data[i]     
        index_array = np.where(np.all(point==unified_verts,axis=1))[0]

        # point not in array yet
        if len(index_array) == 0:
            point = np.expand_dims(point,0)
            unified_verts = np.concatenate((unified_verts,point))
            ref_list.append(len(unified_verts)-1)

        # point already exists
        else:
            ref_list.append(index_array[0])

    return unified_verts, ref_list

cProfile を使用したテスト:

import cProfile
cProfile.run("unify(raw_data)")

私のマシンでは、これは 5.275 秒で実行されます。私はCythonを使用して高速化することについて考えましたが、私が読んだことから、Cythonは通常、numpyメソッドよりもはるかに高速に実行されません. これをより効率的に行う方法に関するアドバイスはありますか?

4

1 に答える 1

2

Jaime は、2D 配列の行に対応する項目を含む 1D 配列として 2D 配列を表示するために使用できる巧妙なトリックを示しました。このトリックを使用すると、1D 配列を入力として受け取る numpy 関数 ( などnp.unique) を高次元配列に適用できます。

の行の順序が重要でunified_vertsない場合 (ref_list が に関して正しい限り)、次のようなハイメのトリックと一緒にunifed_verts使用できます。np.unique

def unify2(raw_data):
    dtype = np.dtype((np.void, (raw_data.shape[1] * raw_data.dtype.itemsize)))
    uniq, inv = np.unique(raw_data.view(dtype), return_inverse=True)
    uniq = uniq.view(raw_data.dtype).reshape(-1, raw_data.shape[1])
    return uniq, inv

結果は、 (または)raw_dataの戻り値から を再構築できるという意味で同じです。unifyunify2

unified, ref = unify(raw_data)
uniq, inv = unify2(raw_data)
assert np.allclose(uniq[inv], unified[ref])  # raw_data

私のマシンでunified, ref = unify(raw_data)は、約 51.390 秒がuniq, inv = unify2(raw_data)必要ですが、約 0.133 秒 (~ 386x 高速化) が必要です。

于 2013-06-24T10:53:25.083 に答える