轴角表示法使用旋转轴 u = ( u x , u y , u z ) \mathbf{u} = (u_x, u_y, u_z) u=(ux,uy,uz) 和旋转角 θ \theta θ 描述旋转。欧拉角转轴角的核心思想是:将三个欧拉旋转等效为绕单一轴的旋转。
推导步骤:
欧拉角→旋转矩阵:
给定欧拉角 ( α , β , γ ) (\alpha, \beta, \gamma) (α,β,γ)(Z-Y-X顺序),旋转矩阵为:
R = R z ( γ ) R y ( β ) R x ( α ) R = R_z(\gamma) R_y(\beta) R_x(\alpha) R=Rz(γ)Ry(β)Rx(α)
其中基本旋转矩阵:
R x ( α ) = [ 1 0 0 0 cos α − sin α 0 sin α cos α ] , R y ( β ) = [ cos β 0 sin β 0 1 0 − sin β 0 cos β ] , R z ( γ ) = [ cos γ − sin γ 0 sin γ cos γ 0 0 0 1 ] R_x(\alpha) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos\alpha & -\sin\alpha \\ 0 & \sin\alpha & \cos\alpha \end{bmatrix}, \quad R_y(\beta) = \begin{bmatrix} \cos\beta & 0 & \sin\beta \\ 0 & 1 & 0 \\ -\sin\beta & 0 & \cos\beta \end{bmatrix}, \quad R_z(\gamma) = \begin{bmatrix} \cos\gamma & -\sin\gamma & 0 \\ \sin\gamma & \cos\gamma & 0 \\ 0 & 0 & 1 \end{bmatrix} Rx(α)= 1000cosαsinα0−sinαcosα ,Ry(β)= cosβ0−sinβ010sinβ0cosβ ,Rz(γ)= cosγsinγ0−sinγcosγ0001
旋转矩阵→轴角:
⚠️ 注意:当 sin θ ≈ 0 \sin\theta \approx 0 sinθ≈0 时需数值稳定处理(如泰勒展开)。
优势:相比欧拉角,轴角表示无万向节死锁问题,且几何意义直观。
#include
#include
#include
#include
#include
#include
#include
// 欧拉角(弧度)转轴角表示
Eigen::AngleAxisd eulerToAxisAngle(double roll, double pitch, double yaw)
{
// 1. 欧拉角→旋转矩阵 (Z-Y-X顺序)
Eigen::Matrix3f rotationMatrix;
rotationMatrix =
Eigen::AngleAxisf(yaw, Eigen::Vector3f::UnitZ()) *
Eigen::AngleAxisf(pitch, Eigen::Vector3f::UnitY()) *
Eigen::AngleAxisf(roll, Eigen::Vector3f::UnitX());
// 2. 旋转矩阵→轴角
Eigen::AngleAxisd axisAngle(rotationMatrix.cast<double>());
// 3. 处理奇点情况 (θ接近0或π)
if (axisAngle.angle() < 1e-7)
{ // 零旋转
axisAngle = Eigen::AngleAxisd(0, Eigen::Vector3d::UnitX());
}
else if (M_PI - axisAngle.angle() < 1e-7)
{ // 180°旋转
Eigen::Matrix3d R = rotationMatrix.cast<double>();
Eigen::Vector3d u(
sqrt((R(0, 0) + 1) / 2),
sqrt((R(1, 1) + 1) / 2),
sqrt((R(2, 2) + 1) / 2)
);
axisAngle = Eigen::AngleAxisd(M_PI, u.normalized());
}
return axisAngle;
}
int main()
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile("target_slice_4000.pcd", *cloud);
double roll = 0.75;
double pitch = 0.5;
double yaw = 0.2;
// 使用示例
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudTran(new pcl::PointCloud<pcl::PointXYZ>);
Eigen::AngleAxisd axisAngle = eulerToAxisAngle(roll, pitch, yaw);
Eigen::Affine3f transform = Eigen::Translation3f(0, 0, 0) * axisAngle.cast<float>();
pcl::transformPointCloud(*cloud, *cloudTran, transform);
return 0;
}