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*3
     Eigen::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(); //初始化全为0
    eTw.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,  // 第一行:旋转+平移x
        sin(theta),  cos(theta), 0, 6,  // 第二行:旋转+平移y
        0,           0,          1, 7,  // 第三行:旋转+平移z
        0,           0,          0, 1;  // 齐次坐标行
    cout <<"T_BA = \n"<<T_BA<<endl;

    // 3. 计算B系中的点P_B = T_BA * P_A
    Eigen::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轴与XZ轴都垂直。

共线 = 三个点 A、B、O 落在 同一条直线上

相关推荐
long_run5 分钟前
C++之auto 关键字
c++
疯狂的代M夫27 分钟前
C++对象的内存布局
开发语言·c++
mit6.8241 小时前
Linux下C#项目构建
开发语言·c#
群联云防护小杜1 小时前
从一次 DDoS 的“死亡回放”看现代攻击链的进化
开发语言·python·linq
霸敛1 小时前
好家园房产中介网后台管理完整(python+flask+mysql)
开发语言·python·flask
重启的码农1 小时前
llama.cpp 分布式推理介绍(4) RPC 服务器 (rpc_server)
c++·人工智能·神经网络
Momentary_SixthSense1 小时前
RESP协议
java·开发语言·javascript·redis·后端·python·mysql
重启的码农1 小时前
llama.cpp 分布式推理介绍(3) 远程过程调用后端 (RPC Backend)
c++·人工智能·神经网络
敲上瘾2 小时前
Linux I/O 多路复用实战:Select/Poll 编程指南
linux·服务器·c语言·c++·select·tcp·poll
huangyuchi.2 小时前
【Linux系统】匿名管道以及进程池的简单实现
linux·运维·服务器·c++·管道·匿名管道·进程池简单实现