3次元の学習データを増やすため、ランダムかつ一様に回転する関数を作りました。手法は色々あるようなのですが、今回は、Shoemake's methodと呼ばれている方法を利用しました。実装例が
http://www.mech.utah.edu/~brannon/public/rotation.pdf
のサブルーチンRNDC (ページA-9)にFortranのコードで示されていましたので、これをPythonで書き直しました。
コードは、
ここか下を参照。3次元のベクトルを入力すると、ランダムに回転させたベクトルが返ります。回転行列がrなので、これを返すようにすれば、色々なベクトルを同じように回転できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 | import numpy as np
import math
def uniform_random_rotate(v):
x0 = np.random.random()
y1 = 2*math.pi*np.random.random()
y2 = 2*math.pi*np.random.random()
r1 = math.sqrt(1.0-x0)
r2 = math.sqrt(x0)
u0 = math.cos(y2)*r2
u1 = math.sin(y1)*r1
u2 = math.cos(y1)*r1
u3 = math.sin(y2)*r2
coefi = 2.0*u0*u0-1.0
coefuu = 2.0
coefe = 2.0*u0
r = np.zeros(shape=(3, 3))
r[0, 0] = coefi+coefuu*u1*u1
r[1, 1] = coefi+coefuu*u2*u2
r[2, 2] = coefi+coefuu*u3*u3
r[1, 2] = coefuu*u2*u3-coefe*u1
r[2, 0] = coefuu*u3*u1-coefe*u2
r[0, 1] = coefuu*u1*u2-coefe*u3
r[2, 1] = coefuu*u3*u2+coefe*u1
r[0, 2] = coefuu*u1*u3+coefe*u2
r[1, 0] = coefuu*u2*u1+coefe*u3
return np.dot(v, r)
|
利用例は以下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | %matplotlib inline
import numpy as np
import math
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from random_rotate import uniform_random_rotate
uvec = np.array([1,0,0])
data = []
for v in range(10000):
data.append(uniform_random_rotate(uvec))
data = np.array(data)
fig = plt.figure(figsize=(15, 10))
ax = fig.add_subplot(111, projection='3d')
ax.scatter3D(data[:,0:1], data[:,1:2], data[:,2:3], s=0.2)
plt.show()
|
プロット結果が以下。
とりあえず見た感じ、半径1の球の表面に一様分布しているように見えます。一様分布をランダムに生成しているのではなくて、ベクトル(1, 0, 0)を一様ランダムに回転させて得られた図です。
0 件のコメント :
コメントを投稿