精华内容
下载资源
问答
  • 学习视觉slam 的入门书籍,配合slam学习笔记起到事半功倍的效果,希望和高博一样能推动slam的发展!
  • 高博SLAM十四教程!百度云
  • 一、环境配置,基本库的安装 1、Eigen库 apt-get 安装 2、sophus库 apt-get 安装 3、pcl 点云库 (1)官方预编译版本 sudo apt-get install libpcl-dev ...卸载 sudo apt-get remove install libpcl-dev ...cmak...

    一、环境配置,基本库的安装

    1、Eigen库

    apt-get 安装

    2、sophus库

    apt-get 安装

    3、pcl 点云库

    (1)官方预编译版本

    sudo apt-get install libpcl-dev

    卸载 sudo apt-get remove install libpcl-dev

    (2)源文件编译)(耗时很长)

    安装一堆依赖库

    git clone

    cmake ..

    make install

    4、kDevelop

    打开工程

    build 

    debug(launch configuratoin 里选择与项目名称相同的那项)

    查看g++版本  g++ -version

    5、opencv3.4.4

    下载源文件编译然后基本的配置

    这里用到了3.4.4版本,需要覆盖原有2.4.9路径

    查看版本 pkg-config --modversion opencv

    二、debug

    1、头文件路径

    预编译版本/usr/include/pcl-1.7/pcl

    源码里没有pcl-1.7 修改的话会引起嵌套问题,于是在include目录新建pcl文件夹,把pcl-1.7下pcl内全部文件移动过去  sudo cp -Rf 命令 

    2、ubuntu16.04 下的常见bug1

    /usr/bin/ld: cannot find -lvtkproj4
    collect2: error: ld returned 1 exit status
    CMakeFiles/joinMap.dir/build.make:350: recipe for target 'joinMap' failed
    make[2]: *** [joinMap] Error 1

    在CMakeList.txt文件里添加

    list(REMOVE_ITEM PCL_LIBRARIES "vtkproj4")

    3、动态链接库bug

    .so文件动态链接库失效

    三、运行例程,实现点云拼接效果

    pcl_viewer 打开生成的点云图就可以啦

    转载于:https://www.cnblogs.com/lqc-nogi/p/10037561.html

    展开全文
  • 高翔视觉slam 14讲

    2018-07-17 20:46:10
    高翔博士视觉slam 14讲的pdf文档,保证是正版,关于视觉slam写得很好的
  • 高博slam资料

    2018-04-22 10:28:22
    slam算法,关于视觉slam十四,以及机器人操作系统ROS浅析
  • 本章的理论内容我已经将其总结在了SLAM14讲学习笔记(六)后端(最难一章:卡尔曼滤波器推导、理解以及扩展)以及SLAM14讲学习笔记(七)后端(BA与图优化,Pose Graph优化的理论与公式详解、因子图优化)当中。...

    本章的理论内容我已经将其总结在了SLAM14讲学习笔记(六)后端(最难一章:卡尔曼滤波器推导、理解以及扩展)以及SLAM14讲学习笔记(七)后端(BA与图优化,Pose Graph优化的理论与公式详解、因子图优化)当中。

    本文主要针对其中的代码进行讲解。


    这章的代码纯粹靠自己学习,对于初学者来说是很难的。

    我个人有些感觉:之前的练习,都是一些小demo,相当于实验内容。而这章,给读者展现了一些工程上的东西。类似于第9讲的设计前端这章已经算一个小型的slam后端系统了。对于普通学生来说,C++的那一套东西,只是懂得理论,主要平时做实验,写代码还是属于面向过程的。从这节的代码中,我们可以充分的学习和体会到面向对象的优势与精髓,了解到工程上的一些设计思想。可能是因为有的一些架构属于C++的内容,而不是后端的理论内容,因此高博没有展开讲解,给初学者造成了困扰。其实他应该放一些笔记和注释在上面,不然谁都不可能无师自通不是吗。

    我把我查资料、参考别的博主的和自己总结的本章带有注释的代码上传到了github主页中:SLAM第10讲后端1-带注释代码


    本章的g2o内容本身相比之前几章,没有什么特殊的难点。g2o的部分内容我之前总结过一节:参见这里。而本节的难点主要在于对整体项目的架构上。例如,common文件夹下的BALProblem跟优化数据txt对接,负责txt的读取、写入,同时还有生成PLY点云文件的功能;BundleParams类负责优化需要的参数值,默认值设定和用户命令行输入等功能。整体这样归类之后,所有优化数据就去BALProblem类对象中询问,参数就去BundleParams类对象询问。关于这些内容,高博并没有给出介绍,在其github主页中,也没有相关的注释文件。因此贸然去学习,感觉是非常困难的。好在有一些大佬已经做了一些探索,参考他们的笔记,可以大大减少我们的学习时间,加快学习效率。

    详情参见:robinhjwy的博客-14讲程序注释

    我对注释中,很多都参考了这位大佬的笔记,感谢有这些人的付出。


    而本章的ceres内容,相比ch6中,增多了很多内容。除了上面的那位大佬,还有其他别的博主做过一些补充。

    详情参见:短者的博客- Ceres-Solver学习笔记(3)

    偷偷吐槽一下:高博在书中写出,相比g2o这样公开文档太少的库,更推荐读者使用Ceres这样的库来做SLAM。然而书中在ch7,8,9都是用的g2o,Ceres相关的内容太少了,还没有注释。可能高博把这个内容放在了课后,希望我们能通过自学来掌握吧。

     

    展开全文
  • 视觉SLAM十四第1010.1 理论部分9.2 实践部分 第10 10.1 理论部分 这一部分算是对第9的补充吧。 1)BA基本问题 之前说过,BA是一种批量处理的非线性优化方法,因此BA的规模是一个不可避免的问题。下面是常见...

    学学停停,发现学是学不完的,但是好歹还想学。
    没有视频资料了(高博的),自学成才(不是)。

    第10讲

    10.1 理论部分

    这一部分算是对第9讲的补充吧。

    1)BA基本问题

    • 之前说过,BA是一种批量处理的非线性优化方法,因此BA的规模是一个不可避免的问题。下面是常见的几种控制规模的方法。
    • ① 从普通帧中选出关键帧,仅构造关键帧与路标点之间的BA。但关键帧数目过多规模同样会增大。
    • 滑动窗口法仅保留离当前时刻最近的N个关键帧。但若相机静止不动,易造成退化问题。因此,有了取时间上靠近,空间上可展开的关键帧的改进。此外,考虑帧间结构深层关系,有了选取共视图中关键帧和路标点进行BA优化的改进。(共视图,指与现在的相机存在共同观测的关键帧构成的图)。
    • 位姿图优化,舍弃对路标点的优化,只保留位姿之间的边。

    2)滑动窗口法

    • 当有新的关键帧进入时,滑动窗口结构会发生改变,因此状态变量将经过新增删除2步操作。
    • 新增:上一时刻已建立N个关键帧的高斯分布,新增关键帧后,仍按照正常BA流程构建N+1个关键帧的高斯分布。
    • 删除:若直接删除一个关键帧,则在边缘化该关键帧时会由于填入操作导致 S \pmb{S} SSS矩阵的路标点块不再是对角块。【稀疏BA要求路标块为对角块,不要求位姿块为对角块】因此,在边缘化某个旧关键帧时,要同时边缘化它观测到的路标点

    3)位姿图

    • 在此前,介绍过的BA优化结构,是常规的以位姿和路标点位置为节点,观测方程为边的图优化模型。而由于若干次观测后收敛的特征点(路标点)位置变化很小的特性,可以构建只有轨迹的图优化,即位姿图优化:仅以位姿为节点,位姿节点之间相对运动的估计为边的图优化模型,路标点位置作为位姿估计的约束。
    • 位姿图优化中,优化变量为各个顶点的位姿,边来自于位姿观测约束。本质上仍旧是最小二乘问题,可用高斯牛顿,L-M法求解。

    9.2 实践部分

    待续ing

    展开全文
  • 小白高博SLAM十四书本程序学习_1 第3 三维空间刚体运动 在高博原始注释上,针对我自己不明白的部分,做额外注释 如果有错误的地方,请大家指点指点 P.48 eigenMatrix.cpp #include <iostream> using ...

    小白高博SLAM十四讲书本程序学习_1
    第3讲 三维空间刚体运动

    在高博原始注释上,针对我自己不明白的部分,做额外注释
    如果有错误的地方,请大家指点指点

    一、P.48 eigenMatrix.cpp

    #include <iostream>
    using namespace std;
    #include <ctime>
    // Eigen 核心部分
    #include <Eigen/Core>
    // 稠密矩阵的代数运算(逆,特征值等)
    #include <Eigen/Dense>
    using namespace Eigen;
    #define MATRIX_SIZE 50
    
    /****************************
    * 本程序演示了 Eigen 基本类型的使用
    ****************************/
    int main(int argc, char **argv) {
      // Eigen 中所有向量和矩阵都是Eigen::Matrix,它是一个模板类。它的前三个参数为:数据类型,行,列
      // 声明一个2*3的float矩阵
      Matrix<float, 2, 3> matrix_23;
      // 同时,Eigen 通过 typedef 提供了许多内置类型,不过底层仍是Eigen::Matrix
      // 例如 Vector3d 实质上是 Eigen::Matrix<double, 3, 1>,即三维向量
      Vector3d v_3d;  //3d d--double  3f f--float
      // 这两者生成结果是一样的
      Matrix<float, 3, 1> vd_3d;
      // Matrix3d 实质上是 Eigen::Matrix<double, 3, 3>
      Matrix3d matrix_33 = Matrix3d::Zero(); //初始化为零
      // 如果不确定矩阵大小,可以使用动态大小的矩阵
      Matrix<double, Dynamic, Dynamic> matrix_dynamic;
      // 更简单的
      MatrixXd matrix_x;
      // 这种类型还有很多,我们不一一列举
    
      // 下面是对Eigen阵的操作
      // 输入数据(初始化)
      matrix_23 << 1, 2, 3, 4, 5, 6;
      // 输出
      cout << "matrix 2x3 from 1 to 6: \n" << matrix_23 << endl;
      // 用()访问矩阵中的元素
      cout << "print matrix 2x3: " << endl;
      for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) cout << matrix_23(i, j) << "\t";
        cout << endl;
      }
      
      // 矩阵和向量相乘(实际上仍是矩阵和矩阵)
      v_3d << 3, 2, 1;
      vd_3d << 4, 5, 6;
      // 但是在Eigen里你不能混合两种不同类型的矩阵,像这样是错的
      // Matrix<double, 2, 1> result_wrong_type = matrix_23 * v_3d;
      // 应该显式转换
      Matrix<double, 2, 1> result = matrix_23.cast<double>() * v_3d;
      cout << "[1,2,3;4,5,6]*[3,2,1]=" << result.transpose() << endl;
      Matrix<float, 2, 1> result2 = matrix_23 * vd_3d;
      cout << "[1,2,3;4,5,6]*[4,5,6]: " << result2.transpose() << endl;
      
      // 同样你不能搞错矩阵的维度
      // 试着取消下面的注释,看看Eigen会报什么错
      // Eigen::Matrix<double, 2, 3> result_wrong_dimension = matrix_23.cast<double>() * v_3d;
    
      // 一些矩阵运算
    
      // 四则运算直接用+-*/即可。
      matrix_33 = Matrix3d::Random();      // 随机数矩阵
      cout << "random matrix: \n" << matrix_33 << endl;
      cout << "transpose: \n" << matrix_33.transpose() << endl;      // 转置
      cout << "sum: " << matrix_33.sum() << endl;            // 各元素和
      cout << "trace: " << matrix_33.trace() << endl;          // 迹
      cout << "times 10: \n" << 10 * matrix_33 << endl;               // 数乘
      cout << "inverse: \n" << matrix_33.inverse() << endl;        // 逆
      cout << "det: " << matrix_33.determinant() << endl;    // 行列式
     
      // 特征值
      // 实对称矩阵可以保证对角化成功
      // SelfAdjointEigenSolver 自伴随特征求解器 Adjoint 伴随矩阵
      SelfAdjointEigenSolver<Matrix3d> eigen_solver(matrix_33.transpose() * matrix_33);
      cout << "Eigen values = \n" << eigen_solver.eigenvalues() << endl;
      cout << "Eigen vectors = \n" << eigen_solver.eigenvectors() << endl;
    
      // 解方程
      // 我们求解 matrix_NN * x = v_Nd 这个方程
      // N的大小在前边的宏里定义,它由随机数生成
      // 直接求逆自然是最直接的,但是求逆运算量大
      Matrix<double, MATRIX_SIZE, MATRIX_SIZE> matrix_NN
          = MatrixXd::Random(MATRIX_SIZE, MATRIX_SIZE);
      matrix_NN = matrix_NN * matrix_NN.transpose();  // 保证半正定
      Matrix<double, MATRIX_SIZE, 1> v_Nd = MatrixXd::Random(MATRIX_SIZE, 1);
      
      clock_t time_stt = clock(); // 计时
      // 直接求逆
      Matrix<double, MATRIX_SIZE, 1> x = matrix_NN.inverse() * v_Nd;
      cout << "time of normal inverse is "
           << 1000 * (clock() - time_stt) / (double) CLOCKS_PER_SEC << "ms" << endl;
      cout << "x = " << x.transpose() << endl;
    
      // 通常用矩阵分解来求,例如QR分解,速度会快很多
      time_stt = clock();
      // colPivHouseholderQr().solve()函数,求解的就是Ax=b中的x
      // x = A.colPivHouseholderQr().solve(b);
      x = matrix_NN.colPivHouseholderQr().solve(v_Nd);  
      cout << "time of Qr decomposition is "
           << 1000 * (clock() - time_stt) / (double) CLOCKS_PER_SEC << "ms" << endl;
      cout << "x = " << x.transpose() << endl;
    
      // 对于正定矩阵,还可以用cholesky分解来解方程
      time_stt = clock();
      // ldlt().solve()函数,求解的就是Ax=b中的x
      // x = A.ldlt().solve(b);
      x = matrix_NN.ldlt().solve(v_Nd);
      cout << "time of ldlt decomposition is "
           << 1000 * (clock() - time_stt) / (double) CLOCKS_PER_SEC << "ms" << endl;
      cout << "x = " << x.transpose() << endl;
    
      return 0;
    }
    

    二、P.62 useGeometry.cpp

    旋转矩阵(3x3):Eigen::Matrix3d
    旋转向量(3x1):Eigen::AngleAxisd
    欧拉角(3x1):Eigen::Vector3d
    四元数(4x1):Eigen::Quaterniond
    欧式变换矩阵:Eigen::Isomotery3d

    #include <iostream>
    #include <cmath>
    #include <Eigen/Core>
    #include <Eigen/Geometry>
    
    using namespace std;
    using namespace Eigen;
    
    // 本程序演示了 Eigen 几何模块的使用方法
    int main(int argc, char **argv) {
      // Eigen/Geometry 模块提供了各种旋转和平移的表示
      // 3D 旋转矩阵直接使用 Matrix3d 或 Matrix3f
      Matrix3d rotation_matrix = Matrix3d::Identity();
    
      // 旋转向量使用 AngleAxis, 它底层不直接是Matrix,但运算可以当作矩阵(因为重载了运算符)
      AngleAxisd rotation_vector(M_PI / 4, Vector3d(0, 0, 1));     //沿 Z 轴旋转 45 度  PI  pi/2 = 90°  pi/4 = 45°  
      
      // cout.precision()其实是输出流cout的一个格式控制函数,也就是在iostream中的一个成员函数。
      // precision()返回当前的浮点数的精度值,而cout.precision(val)其实就是在输出的时候设定输出值以新的浮点数精度值显示,即小数点后保留val位。
      cout.precision(3);
    
      // 旋转向量->矩阵形式 
      // .matrix()
      cout << "rotation matrix =\n" << rotation_vector.matrix() << endl;   //用matrix()转换成矩阵
      // 也可以直接赋值
    
      // 旋转向量->旋转矩阵
      // .toRotationMatrix()
      rotation_matrix = rotation_vector.toRotationMatrix();
    
      // 用 AngleAxis 可以进行坐标变换
      Vector3d v(1, 0, 0);
      Vector3d v_rotated = rotation_vector * v;
      cout << "(1,0,0) after rotation (by angle axis) = " << v_rotated.transpose() << endl;
    
      // 或者用旋转矩阵
      v_rotated = rotation_matrix * v;
      cout << "(1,0,0) after rotation (by matrix) = " << v_rotated.transpose() << endl;
      
      // 欧拉角: 可以将旋转矩阵直接转换成欧拉角
      // 旋转矩阵->欧拉角 
      // .eulerAngles(2, 1, 0); // ZYX顺序,即roll pitch yaw顺序  eulerAngles(0, 1, 2) //XYZ顺序
      Vector3d euler_angles = rotation_matrix.eulerAngles(2, 1, 0); 
      cout << "yaw pitch roll = " << euler_angles.transpose() << endl;
    
      // 欧氏变换矩阵使用 Eigen::Isometry
      Isometry3d T = Isometry3d::Identity();                // 虽然称为3d,实质上是4*4的矩阵
      T.rotate(rotation_vector);                                     // 按照rotation_vector进行旋转
      T.pretranslate(Vector3d(1, 3, 4));                     // 把平移向量设成(1,3,4)
      cout << "Transform matrix = \n" << T.matrix() << endl;
    
      // 用变换矩阵进行坐标变换
      Vector3d v_transformed = T * v;                              // 相当于R*v+t
      cout << "v tranformed = " << v_transformed.transpose() << endl;
    
      // 对于仿射和射影变换,使用 Eigen::Affine3d 和 Eigen::Projective3d 即可,略
      
      // 四元数
      // 可以直接把AngleAxis赋值给四元数,反之亦然
      Quaterniond q = Quaterniond(rotation_vector);
      cout << "quaternion from rotation vector = " << q.coeffs().transpose()
           << endl;  
       // 请注意coeffs的顺序是(x,y,z,w),w为实部,前三者为虚部
      // 也可以把旋转矩阵赋给它
      q = Quaterniond(rotation_matrix);
      cout << "quaternion from rotation matrix = " << q.coeffs().transpose() << endl;
      
      // 使用四元数旋转一个向量,使用重载的乘法即可
      v_rotated = q * v; // 注意数学上是qvq^{-1}  q 乘 v 再乘以 q的逆
      cout << "(1,0,0) after rotation = " << v_rotated.transpose() << endl;
      
      // 用常规向量乘法表示,则应该如下计算
      cout << "should be equal to " << (q * Quaterniond(0, 1, 0, 0) * q.inverse()).coeffs().transpose() << endl;
    
      return 0;
    }
    
    

    三、P.65 coordinateTransform.cpp

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <Eigen/Core>
    #include <Eigen/Geometry>
    
    using namespace std;
    using namespace Eigen;
    
    int main(int argc, char** argv) {
      Quaterniond q1(0.35, 0.2, 0.3, 0.1), q2(-0.5, 0.4, -0.1, 0.2);
      // normalize() 归一化函数
      // 四元数使用前如果没有进行归一化的话,生成的旋转矩阵无法满足正交性
      q1.normalize();  //对四元数进行归一化
      q2.normalize();
      Vector3d t1(0.3, 0.1, 0.1), t2(-0.1, 0.5, 0.3);
      Vector3d p1(0.5, 0, 0.2);
    
    // 以下为初始化(赋值)变换矩阵T 的一种方法,其他见参考文献[2],有详细总结
      Isometry3d T1w(q1), T2w(q2);
      T1w.pretranslate(t1);   //添加平移向量
      T2w.pretranslate(t2);
      Vector3d p2 = T2w * T1w.inverse() * p1;
      cout << endl << p2.transpose() << endl;
      return 0;
    }
    

    四、P.67 plotTrajectory.cpp

    #include <pangolin/pangolin.h>
    #include <Eigen/Core>
    #include <unistd.h>
    
    // 本例演示了如何画出一个预先存储的轨迹
    using namespace std;
    using namespace Eigen;
    
    // path to trajectory file
    string trajectory_file = "./examples/trajectory.txt";
    
    // 这是因为在C++11标准中,aligned_allocator管理C++中的各种数据类型的内存方法是一样的,可以不需要着重写出来。
    // 但是在Eigen管理内存和C++11中的方法是不一样的,所以需要单独强调元素的内存分配和管理。
    void DrawTrajectory(vector<Isometry3d, Eigen::aligned_allocator<Isometry3d>>);
    
    int main(int argc, char **argv) {
      vector<Isometry3d, Eigen::aligned_allocator<Isometry3d>> poses;
      ifstream fin(trajectory_file);
      // 判断是否存在文件
      if (!fin) {
        cout << "cannot find trajectory file at " << trajectory_file << endl;
        return 1;
      }
    
    // .eof 相当于 end
    // eof()函数可以帮助我们用来判断文件是否为空,抑或是判断其是否读到文件结尾
      while (!fin.eof()) {
    // time 为时间,tx,ty,tz 为平移部分,qx,qy,qz,qw 是四元数表示的旋转部分
        double time, tx, ty, tz, qx, qy, qz, qw;
        fin >> time >> tx >> ty >> tz >> qx >> qy >> qz >> qw;
        Isometry3d Twr(Quaterniond(qw, qx, qy, qz)); // 注意归一化问题 这里可能是已经自动normalize()
        Twr.pretranslate(Vector3d(tx, ty, tz));
        poses.push_back(Twr);
      }
      cout << "read total " << poses.size() << " pose entries" << endl;
    
      // draw trajectory in pangolin
      DrawTrajectory(poses);
      return 0;
    }
    
    /*******************************************************************************************/
    // 这是因为在C++11标准中,aligned_allocator管理C++中的各种数据类型的内存方法是一样的,可以不需要着重写出来。
    // 但是在Eigen管理内存和C++11中的方法是不一样的,所以需要单独强调元素的内存分配和管理。
    void DrawTrajectory(vector<Isometry3d, Eigen::aligned_allocator<Isometry3d>> poses) {
    
      // create pangolin window and plot the trajectory
      // 新建一个窗口 
      // 创建名称为“Trajectory Viewer”的GUI窗口,尺寸为1024×768
      pangolin::CreateWindowAndBind("Trajectory Viewer", 1024, 768);
      glEnable(GL_DEPTH_TEST); // 启动深度测试,根据坐标的远近自动隐藏被遮住的图形(材料)。值为2929
      
      /*
      glEnable( GL_BLEND );   // 启用混合
      glDisable( GL_BLEND );  // 禁用关闭混合
     */
      glEnable(GL_BLEND); // 启用颜色混合。例如实现半透明效果。值为3042
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // glBlendFunc 混合函数 混合因子见为知笔记
     // 定义投影和初始模型视图矩阵 
      pangolin::OpenGlRenderState s_cam(
        // 创建一个观察相机视图。
        // ProjectMatrix(int h, int w, int fu, int fv, int cu, int cv, int znear, int zfar)
        // 参数依次为观察相机的图像高度、宽度、4个内参(fx, fy, cx, cy)以及最近和最远视距
        pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000),
        // ModelViewLookAt(double ex, double ey, double ez,double lx, double ly, double lz, double ux, double uy, double uz)
        // 参数依次为相机在世界坐标的位置(相机位置),以及相机镜头对准的物体在世界坐标的位置(一般会设置在原点)(参考点位置)。
        // 假设人站在eye处,眼睛看向( lx, ly, lz ) 这个点,u为相机向上的方向在世界坐标中的方向
        // up vector(上向量)
        pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0)
      );
    
      /*
      创建一个窗口,也就是打开相机后相机有一个成像平面,即视口viewport
      .SetBounds(pangolin::Attach bottom, pangolin::Attach top, pangolin::Attach left, pangolin::Attach right )
      定义面板的位置,其中的参数可以设定成如上0.0,1.0 等(0~1)的相对位置数值,也可以设定成绝对位置数值
      例如:SetBounds(0,1,0,pangolin::Attach::Pix(100))
      前两个参数(0.0, 1.0)表明面板纵向宽度和窗口大小相同 
      后两个参数(0 ,pangolin::Attach::Pix(100))表明右边横向100个像素所有部分用于显示按钮面板
      .SetBound最后一个参数(-1024.0f/768.0f)为显示长宽比
      */
      pangolin::View &d_cam = pangolin::CreateDisplay()
        .SetBounds(0.0, 1.0, 0.0, 1.0, -1024.0f / 768.0f)
        .SetHandler(new pangolin::Handler3D(s_cam));
        
      while (pangolin::ShouldQuit() == false) {
        // 清除屏幕并激活要渲染到的视图
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        d_cam.Activate(s_cam);
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        glLineWidth(2);
        for (size_t i = 0; i < poses.size(); i++) {
          // 画每个位姿的三个坐标轴
          Vector3d Ow = poses[i].translation();
          Vector3d Xw = poses[i] * (0.1 * Vector3d(1, 0, 0));
          Vector3d Yw = poses[i] * (0.1 * Vector3d(0, 1, 0));
          Vector3d Zw = poses[i] * (0.1 * Vector3d(0, 0, 1));
          
        /*
          形状可以设为:  
          GL_POINTS:点            GL_LINES:线          GL_LINE_STRIP:折线
          GL_LINE_LOOP:封闭折线    GL_TRIANGLES:三角形   GL_POLYGON:多边形
          glBegin()和glEnd()之间可以调用的函数有: 
          glVertex()设置顶点坐标     glColor()设置当前颜色       glIndex()设置当前颜色表    
          glNormal()设置法向坐标     glEvalCoord()产生坐标      glCallList(),glCallLists()执行显示列表    
          glTexCoord()设置纹理坐标   glEdgeFlag()控制边界绘制    glMaterial()设置材质
        */
          glBegin(GL_LINES);
          glColor3f(1.0, 0.0, 0.0);
          glVertex3d(Ow[0], Ow[1], Ow[2]);
          glVertex3d(Xw[0], Xw[1], Xw[2]);
          glColor3f(0.0, 1.0, 0.0);
          glVertex3d(Ow[0], Ow[1], Ow[2]);
          glVertex3d(Yw[0], Yw[1], Yw[2]);
          glColor3f(0.0, 0.0, 1.0);
          glVertex3d(Ow[0], Ow[1], Ow[2]);
          glVertex3d(Zw[0], Zw[1], Zw[2]);
          glEnd();
        }
    
        // 画出连线
        for (size_t i = 0; i < poses.size(); i++) {
          glColor3f(0.0, 0.0, 0.0);
          glBegin(GL_LINES);
          auto p1 = poses[i], p2 = poses[i + 1];
          glVertex3d(p1.translation()[0], p1.translation()[1], p1.translation()[2]);
          glVertex3d(p2.translation()[0], p2.translation()[1], p2.translation()[2]);
          glEnd();
        }
    
        pangolin::FinishFrame();
        usleep(5000);   // sleep 5 ms
      }
    }
    
    
    

    [1]: 高翔,张涛. 视觉SLAM十四讲(第二版) [M]. 电子工业出版社, 2019.
    [2]: Eigen库要点
    还查阅了其他许多博客主的文章,在此致谢。本文仅供学习

    展开全文
  • (1)SLAM定义 对比雷达传感器和视觉传感器的优缺点(主要介绍视觉SLAM) 单目:不知道尺度信息 双目:知道尺度信息,但测量范围根据预定的基线相关 RGBD:知道深度信息,但是深度信息对距离也有要求 vSLAM...
  • Tsai分享:资源分享(1)——视觉SLAM十四及视频-附件资源
  • SLAM十四的课件代码,以及标准答案 帮助大家快速入门SLAM
  • 视觉SLAM 14讲 part1-9

    2018-05-19 21:41:37
    附件是高博视觉SLAM十四的1-9,其余部分后续上传。 该书是极好的视觉SLAM入门,另外其对应的程序也是极好的
  • 按照高博博客完成的slam工程代码,可直接运行,,,,,,,,,,,,,,,,,,,
  • 阅读高博slam14讲工程项目那章对前端代码的一些注释,主要是frontend.cpp,其实typedef g2o::BlockSolver_6_3 BlockSolverType中这个<p,l>(本代码中是6,3)一直不是很理解,感觉怎么解释都解释不通,有没有好心...
  • 手写ORB 参考高博slam14讲,经典易懂。对理解orb特征的构建很有帮助,只不过其中的一些思想,比如暴力匹配等,可能效率不高但机具学习价值 /*********************************************************************...
  • 首先,经过思考上一中关于非线性优化的思考:  为何其函数形式为每一个待加项内部求出的H和b相加,而不是把其平方当做fx相加再算总函数做优化?  因为非线性优化的几类方法比如高斯牛顿法Hx=b的形式本就是从 |...
  • 本章的理论内容已经总结到了SLAM14讲学习笔记(九)单目稠密重建、深度滤波器详解与补充(纠正第13讲 建图 中的错误),这章的内容在关键的深度滤波器的地方犯了一些错误,我将其标了出来。本文没有理论知识,对理论...
  • 搞定编译问题之后运行代码出现问题,如下图。尝试装了opencl依旧不行,重新编译也不行。![图片说明]... 而且关闭终端的时候会提示还在运行,不知道怎么回事,希望大佬们指点一下。
  • 视觉slam高博十四 附送ros机器人操作系统简析 高清,完整版
  • 对此,我总结了到了之前的一章中: SLAM14讲学习笔记(十一)g2o图优化中的要点与难点(前端VO中雅克比矩阵的定义) 第二,程序的架构,各个部分的组装。确实如高博所述,这章内容让人体会到了怎么一步一步由砖头...
  • 经典的SLAM/模型由2个方程构成: 如上式所示:上面的为运动方程;下面的为观测方程。 参数: k:时刻 xk:k时刻的相机位姿。(用变换矩阵或李代数表示) uk:输入(运动传感器的读数) yj: 相机位姿为xk时,观测点的路...
  • 学习高博SLAM(1)

    2019-10-06 09:18:24
    这几天按照高博的博客做了一起做RGB-D SLAM (1)和(2) ,,其中大部分步骤都没问题 开发环境是ubuntu14.04+indigo 有几个问题就是: (1)我的电脑不能加载PPA,原因是:用了公司的网络代理,,拿回家用家的...
  • SLAM14讲学习笔记(三)非线性优化基础

    千次阅读 多人点赞 2019-04-01 21:43:29
    这部分的内容,第一次看觉得很难看懂,不知所云;...SLAM14讲学习笔记(七)后端(BA与图优化,Pose Graph优化的理论与公式详解、因子图优化) 其余内容,详见我的 SLAM专栏学习笔记 ,欢迎留言交流。
  • 由于高博的GitHub所提供的14讲第二版代码slambook2中,3rdparty文件夹没有第三方库的源码,需要使用git的submoudle功能管理本书依赖的第三方库,由于不会使用(简单查阅后发现资料较少,不想多花时间在这上面),...
  • 小白高博SLAM十四书本程序学习_2 在高博原始注释上,针对我自己不明白的部分,做额外注释 如果有错误的地方,请大家指点指点 文章目录小白高博SLAM十四书本程序学习_2一、P.87 useSophus.cpp二、P.90 ...
  • 视觉slam14讲学习笔记(持续更新中)

    万次阅读 多人点赞 2017-05-07 21:37:58
    SLAM特指:特指搭载传感器的主体,在没有环境先验的信息情况下,在运动过程中建立环境模型,通过估计自己的运动。 SLAM的目的是解决两个问题:1、定位 2、地图构建 也就是说,要一边估计出传感器自身的位置,一边...
  • 可以在b站上搜索高博视觉slam十四的视频课程,以及他很早以前的博客: https://www.cnblogs.com/gaoxiang12/ 另外推荐专注slam的一个公众号:“泡泡机器人”,同时在b站上也有许多视频课程 opencv的入门可以...
  • 这次的笔记我把13的部分内容总结一下。 虽然slam的名字叫同步定位与构图,但是书中建图的内容却少的可怜。据此高博给出了自己的解释,意为在定位的过程中,我确定了很多特征点的世界坐标,那这个过程其实就是建图...
  • 最近在学习高博的《视觉SLAM14讲》在安装第三方库的时候遇到了不少的问题,好不容易安装完成之后系统又崩了无奈重新装系统,重新安装库。期间唯一的收获就是学会了自己装系统。为了防止系统再次出现问题,讲一些安装...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 769
精华内容 307
关键字:

高博slam14讲