我正在尝试使用pytorch在3D体积上执行刚性+比例转换,但是我似乎无法理解torch.nn.functional.affine_grid所需的theta是如何工作的。
我有一个大小为(1,4,4)的变换矩阵,通过将矩阵平移*比例*旋转相乘而生成。例如,如果我在scipy.ndimage.affine_transform中使用此矩阵,则它可以正常工作。但是,使用torch.nn.functional.affine_grid,相同的矩阵(裁剪为大小(1,3,4))完全失败。
我设法了解了转换的工作原理(-1到1的范围,并且我已经确认了Translation矩阵的工作原理是简单地将值标准化到该范围。至于另外两个,我迷路了。
[我尝试单独使用基本缩放矩阵(如下)作为最基本的比较,但pytorch中的结果与scipy的结果不同
Scaling =
[[0.75, 0, 0, 0],
[[0, 0.75, 0, 0],
[[0, 0, 0.75, 0],
[[0, 0, 0, 1]]
我如何将(1,4,4)仿射矩阵转换为与torch.nn.functional.affine_grid相同?或者,是否有一种方法可以根据转换参数(偏移,欧拉角,缩放比例)生成正确的矩阵?
对于将来遇到类似问题的任何人,scipy与pytorch仿射变换的问题是scipy将变换应用于(0,0,0)周围,而pytorch则将变换应用于图像/体积的中间。
例如,让我们获取参数:
euler_angles = [ea0, ea1, ea2]
translation = [tr0, tr1, tr2]
scale = [sc0, sc1, sc2]
并创建以下转换矩阵:
# Rotation matrix
R_x(ea0, ea1, ea2) = np.array([[1, 0, 0, 0],
[0, math.cos(ea0), -math.sin(ea0), 0],
[0, math.sin(ea0), math.cos(ea0), 0],
[0, 0, 0, 1]])
R_y(ea0, ea1, ea2) = np.array([[math.cos(ea1), 0, math.sin(ea1), 0],
[0, 1, 0, 0],
[-math.sin(ea1), 0, math.cos(ea1)], 0],
[0, 0, 0, 1]])
R_z(ea0, ea1, ea2) = np.array([[math.cos(ea2), -math.sin(ea2), 0, 0],
[math.sin(ea2), math.cos(ea2), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
R = R_x.dot(R_y).dot(R_z)
# Translation matrix
T(tr0, tr1, tr2) = np.array([[1, 0, 0, -tr0],
[0, 1, 0, -tr1],
[0, 0, 1, -tr2],
[0, 0, 0, 1]])
# Scaling matrix
S(sc0, sc1, sc2) = np.array([[1/sc0, 0, 0, 0],
[0, 1/sc1, 0, 0],
[0, 0, 1/sc2, 0],
[0, 0, 0, 1]])
[如果您有一个大小为(100,100,100)的体积,围绕该体积中心进行scipy变换需要先将体积中心移至(0,0,0),然后再将其移回到(在应用了S,T和R之后的50、50、50)。定义:
T_zero = np.array([[1, 0, 0, 50],
[0, 1, 0, 50],
[0, 0, 1, 50],
[0, 0, 0, 1]])
T_centre = np.array([[1, 0, 0, -50],
[0, 1, 0, -50],
[0, 0, 1, -50],
[0, 0, 0, 1]])
然后围绕中心的科学变换是:
transform_scipy_centre = T_zero.dot(T).dot(S).dot(R).T_centre
在pytorch中,参数略有不同。
转换在-1和1之间定义。它们的顺序也不同。以相同(100、100、100)的体积为例,pytorch中的翻译参数如下:
# Note the order difference
translation_pytorch = =[tr0_p, tr1_p, tr2_p] = [tr0/50, tr2/50, tr1/50]
T_p = T(tr0_p, tr1_p, tr2_p)
比例参数的顺序不同:scale_pytorch = [sc0_p,sc1_p,sc2_p] = [sc2,sc0,sc1]S_p = S(sc0_p,sc1_p,sc2_p)
欧拉角是最大的不同。要获得等效的变换,首先参数为负,且顺序不同:
# Note the order difference
euler_angles_pytorch = [ea0_p, ea1_p, ea2_p] = [-ea0, -ea2, -ea1]
R_x_p = R_x(ea0_p, ea1_p, ea2_p)
R_y_p = R_y(ea0_p, ea1_p, ea2_p)
R_z_p = R_z(ea0_p, ea1_p, ea2_p)
旋转矩阵的计算顺序也不同:#注意订单差异R_p = R_x_p.dot(R_z_p).dot(R_y_p)
考虑到所有这些因素,scipy转换为:
transform_scipy_centre = T_zero.dot(T).dot(S).dot(R).T_centre
等价于pytorch转换:
transform_pytorch = T_p.dot(S_p).dot(R_p)
我希望这会有所帮助!