C++中的 Eigen库使用
简介
文章链接:(10 封私信 / 80 条消息) 快速入门矩阵运算——开源库Eigen - 知乎
向量
点积(点乘)
向量点积, 𝑎⋅𝑏=𝑐 ,符号为 ⋅ ,要求向量长度相同,是两个向量之间的点乘运算,结果是一个标量。又称:点乘、数量积、标量积、scalar product、projection product等
叉乘
与向量点乘不同,叉乘仅适用于三维向量,向量叉乘的运算结果是一个向量而不是一个标量。两个向量叉乘所得向量与这两个向量垂直,如下图所示。
矩阵
点积(点乘)
矩阵的点乘(也称为元素乘法)是两个相同大小矩阵之间的一种运算,其结果是一个与这两个矩阵大小相同的新矩阵,其中每个元素都是原矩阵对应位置元素的乘积。
叉乘
矩阵乘法
要求第一个矩阵(左矩阵)的列数与第二个矩阵(右矩阵)的行数相等。假设矩阵 A 是 \(m\times n\) 的矩阵,矩阵 B 是 \(n\times p\) 的矩阵,那么它们的乘积 \(C = AB\) 是一个 \(m\times p\) 的矩阵。其中,C 中第 i 行第 j 列的元素 \(c_{ij}\) 等于 A 的第 i 行元素与 B 的第 j 列对应元素乘积之和 。
矩阵乘法:结果矩阵的维度由参与运算的两个矩阵的行数和列数决定,一般情况下,AB 不一定等于 BA,即矩阵乘法不满足交换律。同时,矩阵乘法满足结合律和分配律,即 \((AB)C = A(BC)\) ,\(A(B + C)=AB + AC\) 。
矩阵乘法:在很多领域都有重要应用,比如在计算机图形学中,用于表示图形的变换(如旋转、平移、缩放等);在机器学习和深度学习中,用于计算神经网络的权重和激活值;在解线性方程组等问题中也起着关键作用。
使用
Eigen::Vector3d
Eigen::Vector3d A(1, 2, 3); //(x1,y1,z1)Eigen::Vector3d B(4, 5, 6);//(x2,y2,z2)Eigen::Vector3d C = A.cross(B); //叉乘 C = A*B = (x3,y3,z3) = (y1*z2 - z1*y2,z1*x2 -x1*z2,x1*y2 - y1*x2) = (2*6-3*5,3*4-1*6,1*5-2*4 ) = (-3 , 6, -3)cout <<"C = \n"<< C.transpose() <<endl; //transpose 转置将3*1 转为1*3Eigen::Vector3d D = B.cross(A);cout <<"D = \n"<< D<<endl;cout << A.dot(B) <<endl;//点乘(4+10+18)
Eigen::Matrix4d
Eigen::Matrix4d eTw;// eTw.setZero(); //初始化全为0eTw.setIdentity(); //对角线为1其他为0 单位矩阵cout <<"eTw = \n"<< eTw<<endl;cout <<"isZero = "<< eTw.isZero(1e-9)<<endl; //不是判断全部为0,可以输入区间检测。cout <<"value ="<< (eTw(1,1) == 0) <<endl;
// 2. 定义A到B的变换矩阵T_B/A(旋转+平移)Eigen::Matrix4d T_BA;// 旋转部分:绕Z轴旋转90度(示例)double theta = M_PI / 2; // 90度弧度cout<<"theta = "<< theta<<endl;T_BA << cos(theta), -sin(theta), 0, 5, // 第一行:旋转+平移xsin(theta), cos(theta), 0, 6, // 第二行:旋转+平移y0, 0, 1, 7, // 第三行:旋转+平移z0, 0, 0, 1; // 齐次坐标行cout <<"T_BA = \n"<<T_BA<<endl;// 3. 计算B系中的点P_B = T_BA * P_AEigen::Vector4d P_B = T_BA * P_A;std::cout << "转换到B系后的坐标: " << P_B.transpose() << std::endl;// 4. 逆转换:从B系转回A系(验证)Eigen::Matrix4d T_AB = T_BA.inverse(); // 求逆矩阵cout <<"T_AB = \n"<<T_AB<<endl;Eigen::Vector4d P_A_back = T_AB * P_B;std::cout << "从B系转回A系的坐标: " << P_A_back.transpose() << std::endl;Eigen::Matrix4d t;t = T_BA;cout << t<<endl;cout<<"===================="<<endl;cout << t.transpose()<<endl;//转置cout<<"===================="<<endl;cout << t.inverse()<<endl; //逆矩阵cout<<"T的转置*t =单位矩阵 \n"<< (t.inverse() *t)<<endl;return 0;
Eigen::norm
在 Eigen 库中,Matrix::norm()
函数默认返回的是弗罗贝尼乌斯范数(Frobenius Norm),也叫欧几里得范数(Euclidean Norm) 的矩阵版本。简单说,就是矩阵所有元素的绝对值的平方和的平方根。
应用场景
Eigen::Vector3d O(177.330, 19.736, 32.725); //原点Eigen::Vector3d X(177.330, 41.935, 13.790);//X坐标点Eigen::Vector3d Y(177.330, 44.744, 17.329);//Y坐标点//计算X轴方向向量Eigen::Vector3d u_x =X -O;cout<< "u_x transpose = "<< u_x.transpose() <<endl;//计算初始 Y 轴方向向量Eigen::Vector3d u_y = Y-O;cout<< "init u_y transpose = "<< u_y.transpose() <<endl;//计算Z轴方向向量 使用叉乘计算Eigen::Vector3d u_z =u_x.cross(u_y);cout<< "u_z transpose = "<< u_z.transpose() <<endl;// 检查是否共线cout <<"u_z.norm = "<< u_z.norm() <<endl;if (u_z.norm() < 1e-6){std::cout << "向量共线,无法创建有效的坐标系。" << std::endl;}//u_y = u_z.cross(u_x); // Y轴方向向量 修正 Y 轴方向// u_x = u_y.cross(u_z);// 通过 Z 轴和 X 轴的叉乘重新计算 Y 轴,确保 X、Y、Z 轴两两垂直(正交化处理),这是关键的修正步骤,正确。cout<< "u_x transpose = "<< u_x.transpose() <<endl;cout<< "u_y transpose = "<< u_y.transpose() <<endl;cout<< "u_z transpose = "<< u_z.transpose() <<endl;// 初始化一个4x4单位矩阵Eigen::Matrix4d UserMatrix;UserMatrix.setIdentity();// 归一化向量u_x.normalize();u_y.normalize();u_z.normalize();UserMatrix <<u_x.x(), u_y.x(), u_z.x(), O.x(),u_x.y(), u_y.y(), u_z.y(), O.y(),u_x.z(), u_y.z(), u_z.z(), O.z(),0, 0, 0, 1;cout <<"UserMatrix = \n "<< UserMatrix<<endl;
为什么需要修正?
在构建三维坐标系时,X、Y、Z 轴必须两两垂直(正交),否则坐标系会 “歪扭”,无法正确描述空间变换(如旋转、平移)。因此:
- 原始
u_y
可能不满足垂直要求,必须通过u_z.cross(u_x)
重新计算(利用叉乘 “垂直于两个输入向量” 的特性 ),确保Y
轴与X
、Z
轴都垂直。
共线 = 三个点 A、B、O 落在 同一条直线上。