这个库是干什么的简单来说transforms3d解决的核心问题是如何在代码中描述和组合三维空间中的旋转、平移、缩放操作。比如你想让一个3D模型绕某个轴旋转45度然后再平移一段距离最后投影到相机平面上——这些操作都需要用到空间变换的数学工具。手动实现这些矩阵运算既容易出错又不便于维护transforms3d就是来帮你解决这个痛点的。几个显著特点和numpy深度绑定输入输出都是ndarray无缝衔接科学计算生态纯Python实现安装简单不依赖C扩展覆盖了工程领域最常用的旋转表示方法及其相互转换安装pipinstalltransforms3d验证是否安装成功importtransforms3dast3dprint(t3d.__version__)模块总览打开transforms3d的源码目录你会发现它是按变换类型来划分模块的子模块负责什么核心数据结构axangles轴角表示法相关转换旋转轴 旋转角度euler欧拉角相关转换三个旋转角quaternions四元数相关运算四元数(w, x, y, z)affines齐次变换矩阵的构建与拆解4x4变换矩阵utils辅助工具函数—理解这个模块划分很重要——当你需要做某种特定转换时直接去对应模块找就行。四种旋转表示法三维旋转在数学上有好几种等效的表示方式各有各的适用场景。transforms3d最大的价值就在于它把这些表示法之间的互相转换封装成了简单的一行函数调用。旋转矩阵旋转矩阵是最直观的一种表示——一个3x3的正交矩阵乘以某个坐标就能得到旋转后的坐标。把轴角转成旋转矩阵importnumpyasnpfromtransforms3d.axanglesimportaxangle2mat# 绕Z轴旋转90度π/2弧度Raxangle2mat([0,0,1],np.pi/2)print(R)# 输出大概长这样# [[ 0. -1. 0.]# [ 1. 0. 0.]# [ 0. 0. 1.]]反过来从旋转矩阵提取轴和角度fromtransforms3d.axanglesimportmat2axangle axis,anglemat2axangle(R)四元数四元数用4个数字(w, x, y, z)来描述旋转最大优势是不会出现万向节锁问题而且在做旋转插值平滑过渡时非常方便。fromtransforms3d.quaternionsimportmat2quat,quat2mat# 旋转矩阵 → 四元数qmat2quat(R)# 结果形如 [0.707, 0, 0, 0.707]# 四元数 → 旋转矩阵R_backquat2mat(q)两个旋转的组合可以通过四元数乘法实现fromtransforms3d.quaternionsimportquatmultiply# 注意四元数乘法不满足交换律顺序很重要q_combinedquatmultiply(q2,q1)# 先应用q1再应用q2欧拉角欧拉角是最符合直觉的表示——分别绕三个坐标轴旋转一定角度就像飞机的俯仰、偏航、滚转。fromtransforms3d.eulerimporteuler2mat,mat2euler# 定义三个旋转角弧度ai,aj,aknp.pi/6,np.pi/4,np.pi/3# 欧拉角 → 旋转矩阵# axes参数控制旋转顺序和坐标系类型# sxyz 静坐标系按X→Y→Z顺序旋转# rzyx 旋转坐标系按Z→Y→X顺序旋转Reuler2mat(ai,aj,ak,axessxyz)# 旋转矩阵 → 欧拉角anglesmat2euler(R,axessxyz)踩坑提醒欧拉角有万向节锁问题——当某个旋转角达到90度时会丢失一个自由度。如果应用场景中角度变化范围大建议用四元数代替。转换关系速查表从 \ 往轴角旋转矩阵四元数欧拉角轴角—axangle2mat先转矩阵再转先转矩阵再转旋转矩阵mat2axangle—mat2quatmat2euler四元数先转矩阵再转quat2mat—先转矩阵再转欧拉角先转矩阵再转euler2mat先转矩阵再转—核心思路旋转矩阵可以作为所有表示法之间的中转站。齐次变换矩阵4x4在实际工程中我们通常需要同时描述旋转和平移。齐次变换矩阵把这两者以及缩放打包到一个4x4矩阵中这样多个变换就可以通过矩阵乘法来组合。构建变换矩阵fromtransforms3d.affinesimportcompose# 定义各分量translation[1.0,2.0,3.0]# 平移量rotationaxangle2mat([0,0,1],np.pi/2)# 旋转绕Z轴90度scaling[2.0,1.0,1.0]# 缩放X方向放大2倍# 合成一个4x4齐次变换矩阵Tcompose(translation,rotation,scaling)拆解变换矩阵拿到一个4x4矩阵后可以反向提取出各个分量fromtransforms3d.affinesimportdecompose44 t,r,z,sdecompose44(T)# t 平移向量# r 旋转矩阵(3x3)# z 缩放向量# s 剪切向量通常为0应用变换到点集fromtransforms3d.affinesimportapply_transform# 定义一批3D点pointsnp.array([[0,0,0],[1,0,0],[1,1,0],[0,1,0],[0,0,1],[1,0,1],[1,1,1],[0,1,1]])# 对所有点应用同一个变换new_pointsapply_transform(points,T)坐标系链多级变换的组合在机器人学中经常需要处理多个坐标系之间的嵌套关系。比如世界坐标系→基座坐标系→末端执行器坐标系每一级都有自己的旋转和平移。transforms3d本身没有提供专门的坐标系链管理类但借助numpy的矩阵乘法这件事变得很简单fromtransforms3d.affinesimportcomposefromtransforms3d.axanglesimportaxangle2mat# 世界坐标系 → 基座坐标系T_world_basecompose(translation[0,0,0.5],# 基座安装高度0.5mrotationaxangle2mat([0,0,1],0),# 无旋转scaling[1,1,1])# 基座坐标系 → 末端执行器T_base_toolcompose(translation[0.3,0,0.2],# 末端位置rotationaxangle2mat([0,1,0],np.pi/4),# 绕Y轴转45度scaling[1,1,1])# 世界坐标系 → 末端执行器矩阵左乘顺序从右到左T_world_toolT_base_tool T_world_base关键点矩阵乘法的顺序是从右到左应用的。T_final T2 T1表示先应用T1再应用T2。搞反这个顺序是最常见的bug来源之一。旋转插值SLERP在动画和轨迹规划场景中经常需要在两个姿态之间做平滑过渡。四元数的球面线性插值Spherical Linear Interpolation简称SLERP就是干这个的。fromtransforms3d.quaternionsimportquat_slerp# 起始姿态无旋转q_start[1,0,0,0]# 结束姿态绕Z轴转90度q_end[0.707,0,0,0.707]# 取中间时刻的插值q_midquat_slerp(q_start,q_end,t0.5)# 生成整条轨迹10个离散点importnumpyasnp trajectory[quat_slerp(q_start,q_end,t)fortinnp.linspace(0,1,10)]平移的插值就更简单了直接用numpy的线性插值startnp.array([0,0,0])endnp.array([1,2,3])# t0.5处的中间位置midstart0.5*(end-start)实战二维机械臂正运动学下面用一个简单的二连杆平面机械臂来演示transforms3d的实际用法importnumpyasnpimporttransforms3dast3ddefcompute_end_effector(joint_angles,link_lengths): 二连杆平面机械臂的正运动学求解 joint_angles: [theta1, theta2] 各关节角度弧度 link_lengths: [l1, l2] 各连杆长度 返回末端执行器的(x, y)坐标 Tnp.eye(4)# 4x4单位矩阵作为初始变换fortheta,lengthinzip(joint_angles,link_lengths):# 每个关节贡献一个旋转平移Rt3d.axangles.axangle2mat([0,0,1],theta)T_linkt3d.affines.compose([length,0,0],R,[1,1,1])TT T_link# 累积变换returnT[:3,3]# 提取平移分量# 计算示例关节角45度和30度连杆长1.0和0.8poscompute_end_effector([np.pi/4,np.pi/6],[1.0,0.8])print(f末端位置: x{pos[0]:.3f}, y{pos[1]:.3f})实战3D点投影到2D图像平面相机标定中一个基本操作就是把世界坐标系中的3D点投影到图像像素坐标上defproject_to_image(points_3d,intrinsic,extrinsic): 3D世界坐标 → 2D图像像素坐标 intrinsic: 3x3 相机内参矩阵 extrinsic: 4x4 世界到相机的外参矩阵 # 转齐次坐标pts_hnp.hstack([points_3d,np.ones((len(points_3d),1))])# 世界坐标 → 相机坐标pts_cam(extrinsic pts_h.T).T# 相机坐标 → 像素坐标pts_img_h(intrinsic pts_cam[:,:3].T).T# 归一化得到像素坐标pts_imgpts_img_h[:,:2]/pts_img_h[:,2:3]returnpts_img和numpy搭配使用的高级技巧transforms3d的所有函数都返回numpy数组这意味着你可以充分利用numpy的向量化能力来处理大规模数据。批量转换多个旋转fromtransforms3d.quaternionsimportquat2mat# 10000个随机四元数quatsnp.random.randn(10000,4)quats/np.linalg.norm(quats,axis1,keepdimsTrue)# 归一化# 批量转旋转矩阵all_matrices[quat2mat(q)forqinquats]不同旋转表示的选择建议场景推荐表示原因做姿态插值/动画四元数SLERP保证最短路径无万向节锁组合多个变换旋转矩阵矩阵乘法天然支持组合接收用户输入/显示欧拉角直观非专业人员也能理解存储和传输轴角只需4个数紧凑数值计算/优化旋转矩阵与线性代数工具链无缝衔接常见报错及解决办法症状根本原因修复方法旋转方向反了左手系和右手系混用确认统一使用右手坐标系某些角度计算结果异常万向节锁换用四元数表示变换结果和预期差很远矩阵乘法顺序搞反记住从右到左原则T T2 T1多次变换后结果漂移浮点误差累积定期对旋转矩阵做正交化处理总结transforms3d虽然功能专一但在三维几何变换这个垂直领域做得非常扎实。掌握它的核心就是理解四种旋转表示法以及它们之间的转换关系然后在实际项目中选择最适合当前场景的表示方式。配合numpy的向量化能力处理大规模空间变换数据也非常高效。
transforms3d库入门指南:Python三维空间变换全解析
这个库是干什么的简单来说transforms3d解决的核心问题是如何在代码中描述和组合三维空间中的旋转、平移、缩放操作。比如你想让一个3D模型绕某个轴旋转45度然后再平移一段距离最后投影到相机平面上——这些操作都需要用到空间变换的数学工具。手动实现这些矩阵运算既容易出错又不便于维护transforms3d就是来帮你解决这个痛点的。几个显著特点和numpy深度绑定输入输出都是ndarray无缝衔接科学计算生态纯Python实现安装简单不依赖C扩展覆盖了工程领域最常用的旋转表示方法及其相互转换安装pipinstalltransforms3d验证是否安装成功importtransforms3dast3dprint(t3d.__version__)模块总览打开transforms3d的源码目录你会发现它是按变换类型来划分模块的子模块负责什么核心数据结构axangles轴角表示法相关转换旋转轴 旋转角度euler欧拉角相关转换三个旋转角quaternions四元数相关运算四元数(w, x, y, z)affines齐次变换矩阵的构建与拆解4x4变换矩阵utils辅助工具函数—理解这个模块划分很重要——当你需要做某种特定转换时直接去对应模块找就行。四种旋转表示法三维旋转在数学上有好几种等效的表示方式各有各的适用场景。transforms3d最大的价值就在于它把这些表示法之间的互相转换封装成了简单的一行函数调用。旋转矩阵旋转矩阵是最直观的一种表示——一个3x3的正交矩阵乘以某个坐标就能得到旋转后的坐标。把轴角转成旋转矩阵importnumpyasnpfromtransforms3d.axanglesimportaxangle2mat# 绕Z轴旋转90度π/2弧度Raxangle2mat([0,0,1],np.pi/2)print(R)# 输出大概长这样# [[ 0. -1. 0.]# [ 1. 0. 0.]# [ 0. 0. 1.]]反过来从旋转矩阵提取轴和角度fromtransforms3d.axanglesimportmat2axangle axis,anglemat2axangle(R)四元数四元数用4个数字(w, x, y, z)来描述旋转最大优势是不会出现万向节锁问题而且在做旋转插值平滑过渡时非常方便。fromtransforms3d.quaternionsimportmat2quat,quat2mat# 旋转矩阵 → 四元数qmat2quat(R)# 结果形如 [0.707, 0, 0, 0.707]# 四元数 → 旋转矩阵R_backquat2mat(q)两个旋转的组合可以通过四元数乘法实现fromtransforms3d.quaternionsimportquatmultiply# 注意四元数乘法不满足交换律顺序很重要q_combinedquatmultiply(q2,q1)# 先应用q1再应用q2欧拉角欧拉角是最符合直觉的表示——分别绕三个坐标轴旋转一定角度就像飞机的俯仰、偏航、滚转。fromtransforms3d.eulerimporteuler2mat,mat2euler# 定义三个旋转角弧度ai,aj,aknp.pi/6,np.pi/4,np.pi/3# 欧拉角 → 旋转矩阵# axes参数控制旋转顺序和坐标系类型# sxyz 静坐标系按X→Y→Z顺序旋转# rzyx 旋转坐标系按Z→Y→X顺序旋转Reuler2mat(ai,aj,ak,axessxyz)# 旋转矩阵 → 欧拉角anglesmat2euler(R,axessxyz)踩坑提醒欧拉角有万向节锁问题——当某个旋转角达到90度时会丢失一个自由度。如果应用场景中角度变化范围大建议用四元数代替。转换关系速查表从 \ 往轴角旋转矩阵四元数欧拉角轴角—axangle2mat先转矩阵再转先转矩阵再转旋转矩阵mat2axangle—mat2quatmat2euler四元数先转矩阵再转quat2mat—先转矩阵再转欧拉角先转矩阵再转euler2mat先转矩阵再转—核心思路旋转矩阵可以作为所有表示法之间的中转站。齐次变换矩阵4x4在实际工程中我们通常需要同时描述旋转和平移。齐次变换矩阵把这两者以及缩放打包到一个4x4矩阵中这样多个变换就可以通过矩阵乘法来组合。构建变换矩阵fromtransforms3d.affinesimportcompose# 定义各分量translation[1.0,2.0,3.0]# 平移量rotationaxangle2mat([0,0,1],np.pi/2)# 旋转绕Z轴90度scaling[2.0,1.0,1.0]# 缩放X方向放大2倍# 合成一个4x4齐次变换矩阵Tcompose(translation,rotation,scaling)拆解变换矩阵拿到一个4x4矩阵后可以反向提取出各个分量fromtransforms3d.affinesimportdecompose44 t,r,z,sdecompose44(T)# t 平移向量# r 旋转矩阵(3x3)# z 缩放向量# s 剪切向量通常为0应用变换到点集fromtransforms3d.affinesimportapply_transform# 定义一批3D点pointsnp.array([[0,0,0],[1,0,0],[1,1,0],[0,1,0],[0,0,1],[1,0,1],[1,1,1],[0,1,1]])# 对所有点应用同一个变换new_pointsapply_transform(points,T)坐标系链多级变换的组合在机器人学中经常需要处理多个坐标系之间的嵌套关系。比如世界坐标系→基座坐标系→末端执行器坐标系每一级都有自己的旋转和平移。transforms3d本身没有提供专门的坐标系链管理类但借助numpy的矩阵乘法这件事变得很简单fromtransforms3d.affinesimportcomposefromtransforms3d.axanglesimportaxangle2mat# 世界坐标系 → 基座坐标系T_world_basecompose(translation[0,0,0.5],# 基座安装高度0.5mrotationaxangle2mat([0,0,1],0),# 无旋转scaling[1,1,1])# 基座坐标系 → 末端执行器T_base_toolcompose(translation[0.3,0,0.2],# 末端位置rotationaxangle2mat([0,1,0],np.pi/4),# 绕Y轴转45度scaling[1,1,1])# 世界坐标系 → 末端执行器矩阵左乘顺序从右到左T_world_toolT_base_tool T_world_base关键点矩阵乘法的顺序是从右到左应用的。T_final T2 T1表示先应用T1再应用T2。搞反这个顺序是最常见的bug来源之一。旋转插值SLERP在动画和轨迹规划场景中经常需要在两个姿态之间做平滑过渡。四元数的球面线性插值Spherical Linear Interpolation简称SLERP就是干这个的。fromtransforms3d.quaternionsimportquat_slerp# 起始姿态无旋转q_start[1,0,0,0]# 结束姿态绕Z轴转90度q_end[0.707,0,0,0.707]# 取中间时刻的插值q_midquat_slerp(q_start,q_end,t0.5)# 生成整条轨迹10个离散点importnumpyasnp trajectory[quat_slerp(q_start,q_end,t)fortinnp.linspace(0,1,10)]平移的插值就更简单了直接用numpy的线性插值startnp.array([0,0,0])endnp.array([1,2,3])# t0.5处的中间位置midstart0.5*(end-start)实战二维机械臂正运动学下面用一个简单的二连杆平面机械臂来演示transforms3d的实际用法importnumpyasnpimporttransforms3dast3ddefcompute_end_effector(joint_angles,link_lengths): 二连杆平面机械臂的正运动学求解 joint_angles: [theta1, theta2] 各关节角度弧度 link_lengths: [l1, l2] 各连杆长度 返回末端执行器的(x, y)坐标 Tnp.eye(4)# 4x4单位矩阵作为初始变换fortheta,lengthinzip(joint_angles,link_lengths):# 每个关节贡献一个旋转平移Rt3d.axangles.axangle2mat([0,0,1],theta)T_linkt3d.affines.compose([length,0,0],R,[1,1,1])TT T_link# 累积变换returnT[:3,3]# 提取平移分量# 计算示例关节角45度和30度连杆长1.0和0.8poscompute_end_effector([np.pi/4,np.pi/6],[1.0,0.8])print(f末端位置: x{pos[0]:.3f}, y{pos[1]:.3f})实战3D点投影到2D图像平面相机标定中一个基本操作就是把世界坐标系中的3D点投影到图像像素坐标上defproject_to_image(points_3d,intrinsic,extrinsic): 3D世界坐标 → 2D图像像素坐标 intrinsic: 3x3 相机内参矩阵 extrinsic: 4x4 世界到相机的外参矩阵 # 转齐次坐标pts_hnp.hstack([points_3d,np.ones((len(points_3d),1))])# 世界坐标 → 相机坐标pts_cam(extrinsic pts_h.T).T# 相机坐标 → 像素坐标pts_img_h(intrinsic pts_cam[:,:3].T).T# 归一化得到像素坐标pts_imgpts_img_h[:,:2]/pts_img_h[:,2:3]returnpts_img和numpy搭配使用的高级技巧transforms3d的所有函数都返回numpy数组这意味着你可以充分利用numpy的向量化能力来处理大规模数据。批量转换多个旋转fromtransforms3d.quaternionsimportquat2mat# 10000个随机四元数quatsnp.random.randn(10000,4)quats/np.linalg.norm(quats,axis1,keepdimsTrue)# 归一化# 批量转旋转矩阵all_matrices[quat2mat(q)forqinquats]不同旋转表示的选择建议场景推荐表示原因做姿态插值/动画四元数SLERP保证最短路径无万向节锁组合多个变换旋转矩阵矩阵乘法天然支持组合接收用户输入/显示欧拉角直观非专业人员也能理解存储和传输轴角只需4个数紧凑数值计算/优化旋转矩阵与线性代数工具链无缝衔接常见报错及解决办法症状根本原因修复方法旋转方向反了左手系和右手系混用确认统一使用右手坐标系某些角度计算结果异常万向节锁换用四元数表示变换结果和预期差很远矩阵乘法顺序搞反记住从右到左原则T T2 T1多次变换后结果漂移浮点误差累积定期对旋转矩阵做正交化处理总结transforms3d虽然功能专一但在三维几何变换这个垂直领域做得非常扎实。掌握它的核心就是理解四种旋转表示法以及它们之间的转换关系然后在实际项目中选择最适合当前场景的表示方式。配合numpy的向量化能力处理大规模空间变换数据也非常高效。