Python 以numpy或scipy格式高效计算3d旋转矩阵列表
我有一个N个单位标准化3D向量的列表p存储在一个带有形状(N,3)的numpy数组中。我还有另一个这样的列表,q。我想计算形状(N,3,3)的N数组U,存储旋转矩阵,将p中的每个点旋转到相应的q 旋转矩阵列表U应满足:Python 以numpy或scipy格式高效计算3d旋转矩阵列表,python,numpy,matrix,scipy,scientific-computing,Python,Numpy,Matrix,Scipy,Scientific Computing,我有一个N个单位标准化3D向量的列表p存储在一个带有形状(N,3)的numpy数组中。我还有另一个这样的列表,q。我想计算形状(N,3,3)的N数组U,存储旋转矩阵,将p中的每个点旋转到相应的q 旋转矩阵列表U应满足: np.all(np.einsum('ijk,ik->ij', U, p) == q) 在逐点的基础上,问题归结为能够计算绕某个轴旋转一定角度的旋转矩阵。解决单点情况的代码如下所示: def rotation_matrix(angle, direction): d
np.all(np.einsum('ijk,ik->ij', U, p) == q)
在逐点的基础上,问题归结为能够计算绕某个轴旋转一定角度的旋转矩阵。解决单点情况的代码如下所示:
def rotation_matrix(angle, direction):
direction = np.atleast_1d(direction).astype('f4')
sina = np.sin(angle)
cosa = np.cos(angle)
direction = direction/np.sqrt(np.sum(direction*direction))
R = np.diag([cosa, cosa, cosa])
R += np.outer(direction, direction) * (1.0 - cosa)
direction *= sina
R += np.array(((0.0, -direction[2], direction[1]),
(direction[2], 0.0, -direction[0]),
(-direction[1], direction[0], 0.0)))
return R
我需要的是一个与上述函数完全相同的函数,但它不接受单个角度和单个方向,而是接受一个角度形状数组(npts,)和一个方向形状数组(npts,3)。下面的代码只完成了一部分-问题是np.diag
和np.outer
都不接受axis
参数
def rotation_matrices(angles, directions):
directions = np.atleast_2d(directions)
angles = np.atleast_1d(angles)
npts = directions.shape[0]
directions = directions/np.sqrt(np.sum(directions*directions, axis=1)).reshape((npts, 1))
sina = np.sin(angles)
cosa = np.cos(angles)
# Lines below require extension to 2d case - np.diag and np.outer do not support axis arguments
R = np.diag([cosa, cosa, cosa])
R += np.outer(directions, directions) * (1.0 - cosa)
directions *= sina
R += np.array(((0.0, -directions[2], directions[1]),
(directions[2], 0.0, -directions[0]),
(-directions[1], directions[0], 0.0)))
return R
numpy或scipy是否有一个紧凑的矢量化函数,以避免使用for循环的方式计算适当的旋转矩阵?问题是np.diag
和np.outer
都不接受axis
作为参数。我的应用程序必须非常大,1e7或更大,因此出于性能原因,有必要使用一个矢量化函数来保持所有相关轴对齐 现在把这个放在这里,稍后会解释。使用@jaime答案中的levi-cevita符号和罗德里格斯公式的矩阵形式以及基于k=(a x b)/sin(θ)
编辑:当。问题变了
def rotation_matrices(angles, directions):
eijk = np.zeros((3, 3, 3))
eijk[0, 1, 2] = eijk[1, 2, 0] = eijk[2, 0, 1] = 1
eijk[0, 2, 1] = eijk[2, 1, 0] = eijk[1, 0, 2] = -1
theta = angles[:, None, None]
K = directions.dot(eijk)
return np.eye(3) + K * np.sin(theta) + K @ K * (1 - np.cos(theta))
为Nx3x3矩阵的批量旋转滴下另一个解决方案。其中3x3分量表示中的矢量分量
[[11, 12, 13],
[21, 22, 23],
[31, 32, 33]]
现在,通过np.einsum
进行的矩阵旋转是:
data=np.random.uniform(大小=(500,3,3))
rotmat=np.随机.均匀(尺寸=(3,3))
数据(rot=np.einsum('ij,…jk,lk->…il',rotmat,data,rotmat)
这相当于
对于数据中的数据:
np.dot(np.dot(rotmat,data_mat),rotmat.T)
在np.dot
-循环上的加速比大约是250倍。对我来说更像是一个数学问题。而且,我很确定它不是唯一的。(将p映射到q后,仍然可以围绕q自由旋转)您可能希望查找同质坐标/变换,后者是用于将一组坐标从一个坐标系转换到另一个坐标系的矩阵。我不认为有任何python包可以做到这一点,但是计算应该很容易用numpy实现。嗯,我看到了你的点@PaulPanzer,但我仍然感到困惑,因为每对3d点定义了一个唯一的平面,它定义了一个唯一的法向量,关于法向量,有一个唯一的旋转角,它把p旋转成q。否?您可以使用R[:,range(3),range(3)]+=…
设置对角线(假设您先做外积。否则您必须先使用zero
创建R
)回答得好,@DanielF。很抱歉编辑了你的问题。我已经检查了你的旋转矩阵函数输出是否与评论中概述的方法完全一致。因为你花了时间写了出来,所以我会把这个作为公认的答案来核对。尽管这个解决方案非常快,但我要提到的是,注释中的方法对于非常多的点来说要快约2倍。另外,它不是K@K
返回语句中的操作,该语句仅适用于Python3,可替换为np.matmul(K,K)
为了同时容纳python 2和python 3用户,我并不真正理解您的解决方案如何提取多个旋转矩阵。你能再详细一点吗。据我所知,您的Nx3x3是提取的旋转矩阵,对吗?是的,Nx3x3是输入矩阵(data
),通过rotmat
[[11, 12, 13],
[21, 22, 23],
[31, 32, 33]]