在python中将由Euler角度定义的旋转应用于3D图像
我正在处理3D图像,必须根据“zxz”约定中的欧拉角(φ、psi、θ)旋转它们(这些欧拉角是数据集的一部分,所以我必须使用该约定)。我发现函数scipy.ndimage.rotate在这方面似乎很有用在python中将由Euler角度定义的旋转应用于3D图像,python,image-processing,3d,image-rotation,euler-angles,Python,Image Processing,3d,Image Rotation,Euler Angles,我正在处理3D图像,必须根据“zxz”约定中的欧拉角(φ、psi、θ)旋转它们(这些欧拉角是数据集的一部分,所以我必须使用该约定)。我发现函数scipy.ndimage.rotate在这方面似乎很有用 arrayR = scipy.ndimage.rotate(array , phi, axes=(0,1), reshape=False) arrayR = scipy.ndimage.rotate(arrayR, psi, axes=(1,2), reshape=False) arrayR =
arrayR = scipy.ndimage.rotate(array , phi, axes=(0,1), reshape=False)
arrayR = scipy.ndimage.rotate(arrayR, psi, axes=(1,2), reshape=False)
arrayR = scipy.ndimage.rotate(arrayR, the, axes=(0,1), reshape=False)
可悲的是,这并没有达到预期的效果。这就是为什么:
定义:
在z-x-z约定中,x-y-z帧旋转三次:第一次
绕z轴旋转一个角度φ;然后通过一个
角度psi;然后,以θ角对最新的z轴进行调整
但是,对于上述代码,旋转始终相对于原始轴。这就是为什么获得的旋转是不正确的。有人建议获得正确的旋转,如定义中所述
换句话说,在当前的“zxz”约定中,旋转是固有的(围绕旋转坐标系XYZ的轴旋转,与运动物体保持一致,在每次元素旋转后改变其方向)。如果我使用上面的代码,旋转是外在的(围绕原始坐标系的xyz轴旋转,假设该坐标系保持不变)。我需要一种在python中进行外部旋转的方法。
我通过这个链接找到了一个令人满意的解决方案: 该方法使用np.meshgrid、scipy.ndimage.map_坐标。上面的链接使用一些第三方库来生成旋转矩阵,但是我使用scipy.spatial.transform.rotation。此函数允许定义内部和外部旋转:请参见scipy.spatial.transform.Rotation.from_euler的说明 以下是我的功能:
import numpy as np
from scipy.spatial.transform import Rotation as R
from scipy.ndimage import map_coordinates
# Rotates 3D image around image center
# INPUTS
# array: 3D numpy array
# orient: list of Euler angles (phi,psi,the)
# OUTPUT
# arrayR: rotated 3D numpy array
# by E. Moebel, 2020
def rotate_array(array, orient):
phi = orient[0]
psi = orient[1]
the = orient[2]
# create meshgrid
dim = array.shape
ax = np.arange(dim[0])
ay = np.arange(dim[1])
az = np.arange(dim[2])
coords = np.meshgrid(ax, ay, az)
# stack the meshgrid to position vectors, center them around 0 by substracting dim/2
xyz = np.vstack([coords[0].reshape(-1) - float(dim[0]) / 2, # x coordinate, centered
coords[1].reshape(-1) - float(dim[1]) / 2, # y coordinate, centered
coords[2].reshape(-1) - float(dim[2]) / 2]) # z coordinate, centered
# create transformation matrix
r = R.from_euler('zxz', [phi, psi, the], degrees=True)
mat = r.as_matrix()
# apply transformation
transformed_xyz = np.dot(mat, xyz)
# extract coordinates
x = transformed_xyz[0, :] + float(dim[0]) / 2
y = transformed_xyz[1, :] + float(dim[1]) / 2
z = transformed_xyz[2, :] + float(dim[2]) / 2
x = x.reshape((dim[1],dim[0],dim[2]))
y = y.reshape((dim[1],dim[0],dim[2]))
z = z.reshape((dim[1],dim[0],dim[2])) # reason for strange ordering: see next line
# the coordinate system seems to be strange, it has to be ordered like this
new_xyz = [y, x, z]
# sample
arrayR = map_coordinates(array, new_xyz, order=1)
注:
您也可以将此函数用于固有旋转,只需将“from_euler”的第一个参数调整为您的euler约定。在本例中,您获得了与我的第一篇文章中相同的结果(使用scipy.ndimage.rotate)。但是,我注意到当前代码比使用scipy.ndimage.rotate(40^3卷为0.03s)快3倍(40^3卷为0.01s)
希望这能帮助别人 我通过这个链接找到了一个令人满意的解决方案: 该方法使用np.meshgrid、scipy.ndimage.map_坐标。上面的链接使用一些第三方库来生成旋转矩阵,但是我使用scipy.spatial.transform.rotation。此函数允许定义内部和外部旋转:请参见scipy.spatial.transform.Rotation.from_euler的说明 以下是我的功能:
import numpy as np
from scipy.spatial.transform import Rotation as R
from scipy.ndimage import map_coordinates
# Rotates 3D image around image center
# INPUTS
# array: 3D numpy array
# orient: list of Euler angles (phi,psi,the)
# OUTPUT
# arrayR: rotated 3D numpy array
# by E. Moebel, 2020
def rotate_array(array, orient):
phi = orient[0]
psi = orient[1]
the = orient[2]
# create meshgrid
dim = array.shape
ax = np.arange(dim[0])
ay = np.arange(dim[1])
az = np.arange(dim[2])
coords = np.meshgrid(ax, ay, az)
# stack the meshgrid to position vectors, center them around 0 by substracting dim/2
xyz = np.vstack([coords[0].reshape(-1) - float(dim[0]) / 2, # x coordinate, centered
coords[1].reshape(-1) - float(dim[1]) / 2, # y coordinate, centered
coords[2].reshape(-1) - float(dim[2]) / 2]) # z coordinate, centered
# create transformation matrix
r = R.from_euler('zxz', [phi, psi, the], degrees=True)
mat = r.as_matrix()
# apply transformation
transformed_xyz = np.dot(mat, xyz)
# extract coordinates
x = transformed_xyz[0, :] + float(dim[0]) / 2
y = transformed_xyz[1, :] + float(dim[1]) / 2
z = transformed_xyz[2, :] + float(dim[2]) / 2
x = x.reshape((dim[1],dim[0],dim[2]))
y = y.reshape((dim[1],dim[0],dim[2]))
z = z.reshape((dim[1],dim[0],dim[2])) # reason for strange ordering: see next line
# the coordinate system seems to be strange, it has to be ordered like this
new_xyz = [y, x, z]
# sample
arrayR = map_coordinates(array, new_xyz, order=1)
注:
您也可以将此函数用于固有旋转,只需将“from_euler”的第一个参数调整为您的euler约定。在本例中,您获得了与我的第一篇文章中相同的结果(使用scipy.ndimage.rotate)。但是,我注意到当前代码比使用scipy.ndimage.rotate(40^3卷为0.03s)快3倍(40^3卷为0.01s)
希望这能帮助别人