跳到主要内容旋转矩阵、齐次变换矩阵、欧拉角与四元数相互转换 C++ Python 实现 | 极客日志编程语言AI算法
旋转矩阵、齐次变换矩阵、欧拉角与四元数相互转换 C++ Python 实现
综述由AI生成提供基于 C++(Eigen)和 Python(NumPy + SciPy)的姿态转换工具库实现。内容涵盖旋转矩阵、齐次变换矩阵、欧拉角(Z-Y-X 顺序)、四元数(wxyz 格式)之间的相互转换函数。文章明确了右手坐标系、单位及接口规范,提供了可直接复用的头文件与模块代码示例,并建议了项目结构与扩展方向,适用于机器人、控制及 SLAM 等领域的开发。
kaikai30 浏览 本文旨在基于 C++ 和 Python,使用常用库实现旋转矩阵、齐次变换矩阵、欧拉角、四元数之间的相互转换,并提供长期可复用的代码库。
0. 全局统一约定(极其重要)
下面所有 C++ / Python 代码都遵循同一套约定:
- 右手坐标系:
- x 轴:前
- y 轴:左
- z 轴:上
(典型移动机器人/航空/SLAM 约定)
- 欧拉角定义:
roll:绕 x 轴旋转
pitch:绕 y 轴旋转
yaw:绕 z 轴旋转
- 采用 Z-Y-X 顺序(yaw, pitch, roll),即旋转矩阵:
R = Rz(yaw) * Ry(pitch) * Rx(roll)
- 四元数形式:
- 使用数学常用表示:
q = (w, x, y, z)
- 内部库如 Eigen / SciPy 可能用
(x, y, z, w),我们在封装函数里统一成 (w, x, y, z) 接口。
- 旋转矩阵 R:
- 3×3 正交矩阵,列向量为坐标轴在世界坐标中的方向
- 满足
v_world = R * v_body(列向量右乘的习惯)
- 齐次变换矩阵 T (4×4):
- T 表示从 A 坐标系到 B 坐标系的刚体变换
- 形式:T = [R t; 0 1]
- 向量变换:p_B_hom = T_BA * p_A_hom
1. C++ 版(基于 Eigen)的统一接口
1.1 头文件示例:pose_utils_eigen.h
#pragma once
#include <Eigen/Core>
#include <Eigen/Geometry>
using Vec3 = Eigen::Vector3d;
using Mat3 = Eigen::Matrix3d;
Mat4 = Eigen::Matrix4d;
Quat = Eigen::Quaterniond;
{
Mat3 R;
R = Eigen::(yaw, Vec3::()) * Eigen::(pitch, Vec3::()) * Eigen::(roll, Vec3::());
R;
}
{
Eigen::Vector3d euler = R.(, , );
yaw = euler[];
pitch = euler[];
roll = euler[];
Eigen::(roll, pitch, yaw);
}
{
;
q.();
q.();
}
{
;
q.();
Eigen::(q.(), q.(), q.(), q.());
}
{
Mat3 R = (roll, pitch, yaw);
(R);
}
{
Mat3 R = (w, x, y, z);
(R);
}
{
Mat4 T = Mat4::();
T.<, >() = R;
T.<, >() = t;
T;
}
{
R = T.<, >();
t = T.<, >();
}
{
Mat3 R = (roll, pitch, yaw);
;
(R, t);
}
{
Mat3 R;
Vec3 t;
(T, R, t);
Eigen::Vector3d rpy = (R);
roll = rpy[];
pitch = rpy[];
yaw = rpy[];
tx = t[];
ty = t[];
tz = t[];
}
{
Mat3 R = (w, x, y, z);
;
(R, t);
}
{
Mat3 R;
Vec3 t;
(T, R, t);
Eigen::Vector4d q = (R);
w = q[];
x = q[];
y = q[];
z = q[];
tx = t[];
ty = t[];
tz = t[];
}
using
using
inline Mat3 euler_to_rot(double roll, double pitch, double yaw)
AngleAxisd
UnitZ
AngleAxisd
UnitY
AngleAxisd
UnitX
return
inline Eigen::Vector3d rot_to_euler(const Mat3& R)
eulerAngles
2
1
0
double
0
double
1
double
2
return
Vector3d
inline Mat3 quat_to_rot(double w, double x, double y, double z)
Quat q(x, y, z, w)
normalize
return
toRotationMatrix
inline Eigen::Vector4d rot_to_quat(const Mat3& R)
Quat q(R)
normalize
return
Vector4d
w
x
y
z
inline Eigen::Vector4d euler_to_quat(double roll, double pitch, double yaw)
euler_to_rot
return
rot_to_quat
inline Eigen::Vector3d quat_to_euler(double w, double x, double y, double z)
quat_to_rot
return
rot_to_euler
inline Mat4 rt_to_T(const Mat3& R, const Vec3& t)
Identity
topLeftCorner
3
3
topRightCorner
3
1
return
inline void T_to_rt(const Mat4& T, Mat3& R, Vec3& t)
topLeftCorner
3
3
topRightCorner
3
1
inline Mat4 euler_t_to_T(double roll, double pitch, double yaw, double tx, double ty, double tz)
euler_to_rot
Vec3 t(tx, ty, tz)
return
rt_to_T
inline void T_to_euler_t(const Mat4& T, double& roll, double& pitch, double& yaw, double& tx, double& ty, double& tz)
T_to_rt
rot_to_euler
0
1
2
0
1
2
inline Mat4 quat_t_to_T(double w, double x, double y, double z, double tx, double ty, double tz)
quat_to_rot
Vec3 t(tx, ty, tz)
return
rt_to_T
inline void T_to_quat_t(const Mat4& T, double& w, double& x, double& y, double& z, double& tx, double& ty, double& tz)
T_to_rt
rot_to_quat
0
1
2
3
0
1
2
你可以把这整个头文件直接收录到自己的 C++ 工程中作为公共工具。
2. Python 版(NumPy + SciPy Rotation)
假设你可以安装 SciPy。如果暂时没有 SciPy,也可以只用 NumPy + 手写公式。
2.1 依赖安装
2.2 模块示例:pose_utils.py
""" 统一的姿态/位姿转换工具
约定:
- 右手系
- 欧拉角(roll, pitch, yaw), 旋转顺序 Z-Y-X: R = Rz(yaw) * Ry(pitch) * Rx(roll)
- 四元数接口形式 (w, x, y, z)
- 旋转矩阵 R: shape (3,3), v_world = R @ v_body
- 齐次变换 T: shape (4,4) = [R t; 0 1]
"""
import numpy as np
from scipy.spatial.transform import Rotation as R_
def euler_to_rot(roll: float, pitch: float, yaw: float) -> np.ndarray:
""" 欧拉角 -> 旋转矩阵
输入单位:弧度
顺序:Z-Y-X (yaw, pitch, roll)
"""
r = R_.from_euler('zyx', [yaw, pitch, roll])
return r.as_matrix()
def rot_to_euler(R: np.ndarray) -> np.ndarray:
""" 旋转矩阵 -> 欧拉角
返回:[roll, pitch, yaw] (弧度)
"""
R = np.asarray(R, dtype=float).reshape(3, 3)
r = R_.from_matrix(R)
yaw, pitch, roll = r.as_euler('zyx')
return np.array([roll, pitch, yaw])
def quat_to_rot(q: np.ndarray) -> np.ndarray:
""" 四元数 -> 旋转矩阵
q: [w, x, y, z]
返回:R (3,3)
"""
q = np.asarray(q, dtype=float).flatten()
w, x, y, z = q
r = R_.from_quat([x, y, z, w])
return r.as_matrix()
def rot_to_quat(R: np.ndarray) -> np.ndarray:
""" 旋转矩阵 -> 四元数
返回:[w, x, y, z]
"""
R = np.asarray(R, dtype=float).reshape(3, 3)
r = R_.from_matrix(R)
x, y, z, w = r.as_quat()
return np.array([w, x, y, z])
def euler_to_quat(roll: float, pitch: float, yaw: float) -> np.ndarray:
""" 欧拉角 -> 四元数
返回:[w, x, y, z]
"""
R = euler_to_rot(roll, pitch, yaw)
return rot_to_quat(R)
def quat_to_euler(q: np.ndarray) -> np.ndarray:
""" 四元数 -> 欧拉角
q: [w, x, y, z]
返回:[roll, pitch, yaw]
"""
R = quat_to_rot(q)
return rot_to_euler(R)
def rt_to_T(R: np.ndarray, t: np.ndarray) -> np.ndarray:
""" (R, t) -> 齐次变换矩阵 T
R: (3,3) t: (3,)
返回:T (4,4) = [R t; 0 1]
"""
R = np.asarray(R, dtype=float).reshape(3, 3)
t = np.asarray(t, dtype=float).reshape(3,)
T = np.eye(4)
T[:3, :3] = R
T[:3, 3] = t
return T
def T_to_rt(T: np.ndarray):
""" 齐次变换矩阵 T -> (R, t)
返回:R(3,3), t(3,)
"""
T = np.asarray(T, dtype=float).reshape(4, 4)
R = T[:3, :3]
t = T[:3, 3]
return R, t
def euler_t_to_T(roll: float, pitch: float, yaw: float, tx: float, ty: float, tz: float) -> np.ndarray:
""" (欧拉角, t) -> T
"""
R = euler_to_rot(roll, pitch, yaw)
t = np.array([tx, ty, tz], dtype=float)
return rt_to_T(R, t)
def T_to_euler_t(T: np.ndarray):
""" T -> (欧拉角, t)
返回:roll, pitch, yaw, tx, ty, tz
"""
R, t = T_to_rt(T)
roll, pitch, yaw = rot_to_euler(R)
tx, ty, tz = t
return roll, pitch, yaw, tx, ty, tz
def quat_t_to_T(q: np.ndarray, t: np.ndarray) -> np.ndarray:
""" (四元数, t) -> T
q: [w, x, y, z] t: (3,)
"""
R = quat_to_rot(q)
return rt_to_T(R, t)
def T_to_quat_t(T: np.ndarray):
""" T -> (四元数, t)
返回:q: [w, x, y, z], t: (3,)
"""
R, t = T_to_rt(T)
q = rot_to_quat(R)
return q, t
3. 转换关系一览(思维导图式)
在这个 C++ / Python 库中,实际上是围绕几条'主干'做封装:
欧拉角 ⇄ 旋转矩阵
四元数 ⇄ 旋转矩阵
(R, t) ⇄ T
- 其他组合,例如:
欧拉角 ⇄ 四元数:通过 欧拉角 -> R -> 四元数 / 四元数 -> R -> 欧拉角
(欧拉角, t) ⇄ T:通过 欧拉角 -> R + rt ⇄ T
(四元数, t) ⇄ T:通过 四元数 -> R + rt ⇄ T
这样一方面接口清晰,另一方面将来如果你要替换内部实现(比如用手写三角公式、用别的库),只要保证每条主干的语义不变即可。
4. 建议的项目结构与使用方式
C++
include/
pose_utils_eigen.h
src/
tests/
test_pose_utils.cpp
#include "pose_utils_eigen.h"
int main() {
double roll = 0.1, pitch = 0.2, yaw = 0.3;
Eigen::Matrix3d R = euler_to_rot(roll, pitch, yaw);
Eigen::Vector4d q = rot_to_quat(R);
Eigen::Matrix4d T = euler_t_to_T(roll, pitch, yaw, 1.0, 2.0, 3.0);
return 0;
}
Python
pose_utils/
__init__.py
pose_utils.py
tests/
test_pose_utils.py
from pose_utils.pose_utils import euler_to_quat, quat_to_euler, euler_t_to_T
roll, pitch, yaw = 0.1, 0.2, 0.3
q = euler_to_quat(roll, pitch, yaw)
T = euler_t_to_T(roll, pitch, yaw, 1.0, 2.0, 3.0)
5. 后续可以扩展的方向(预留)
- 不同欧拉顺序:例如 XYZ、ZXY 等,在函数名中显式写明,比如
euler_xyz_to_rot。
- 度/弧度转换:提供
*_deg 版本;或在函数里增加参数 degrees=False/True。
- 与 ROS tf / tf2 的互操作:在 C++ / Python 分别写
from_tf_quat / to_tf_quat,做 (x,y,z,w) 与 (w,x,y,z) 的适配。
- 转移矩阵方向区分:例如
T_ab、T_ba 一套函数,对逆变换进行封装。
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- 随机西班牙地址生成器
随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online