欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

视觉SLAM十四讲——第九讲实践:设计前端

程序员文章站 2024-03-24 23:48:34
...

@ 《视觉SLAM十四讲》知识点与习题

《视觉SLAM十四讲》第九讲知识点整理+习题

正在学习SLAM相关知识,将一些关键点及时记录下来。

知识点整理

本章很有趣,将前面的知识点都联系在了一起,而且还会通过一系列方法解决诸如:相机运动过快、图像模糊、误匹配等实际问题

  1. 单目视觉相对复杂,RGB-D最为简单,没有初始化,也没有尺度问题
  2. 数据单元
    1. : 将认为重要的帧保存起来,并认为相机轨迹可以用这些关键帧来描述,多基于工程经验
    2. 路标:图像中的特征点。在相机运动后,还能估计路标的3D位置。通常,将路标点放在一个地图当中,并将新来的帧与地图中的路标点进行匹配,估计相机位姿
  3. 视觉里程计:Frame, Camera, MapPoint, Map以及Config

代码

  1. Camera类:注意,根据书本P60页的写法,T_c_w表示世界坐标系到相机坐标系间的变换,即世界坐标系在相机坐标系下的表示,按照顺序记也许比较好记:c在w前,即从相机坐标系变换到世界坐标系。p_c=T_c_w p_w,表示当前点P在相机坐标系中的坐标=(世界坐标系在相机坐标系下的表示)*(P在世界坐标系中的坐标)。每个函数的注解在下方代码中。注意:相机和世界坐标系之间的变换涉及的是相机位姿,而相机坐标系和像素坐标系之间的变换涉及的是相机内参
    //输入为P点在世界坐标系下的表示,并且给出相机坐标系在世界坐标系下的位姿,输出为当前变换在相机坐标系下的表示
    Vector3d Camera::world2camera ( const Vector3d& p_w, const SE3& T_c_w )
    {
        return T_c_w*p_w;
    }
    //输入为P点在相机坐标系下的表示,并且给出相机坐标系在世界坐标系下的位姿,输出为当前变换在世界坐标系下的表示
    Vector3d Camera::camera2world ( const Vector3d& p_c, const SE3& T_c_w )
    {
        return T_c_w.inverse() *p_c;
    }
    //输入为P点在相机坐标系下的表示,输出为其在像素坐标系中的表示
    Vector2d Camera::camera2pixel ( const Vector3d& p_c )
    {
        return Vector2d (
            fx_ * p_c ( 0,0 ) / p_c ( 2,0 ) + cx_,
            fy_ * p_c ( 1,0 ) / p_c ( 2,0 ) + cy_
        );
    }
    //输入为P点在像素坐标系下的表示,输出为其在相机坐标系中的表示
    Vector3d Camera::pixel2camera ( const Vector2d& p_p, double depth )
    {
        return Vector3d (
            ( p_p ( 0,0 )-cx_ ) *depth/fx_,
            ( p_p ( 1,0 )-cy_ ) *depth/fy_,
            depth
        );
    }
    //输入输出上述几个函数中已经介绍过,变换过程为:先得出P点在相机坐标系下的表示,然后再变换到像素坐标系中即可
    Vector2d Camera::world2pixel ( const Vector3d& p_w, const SE3& T_c_w )
    {
        return camera2pixel ( world2camera ( p_w, T_c_w ) );
    }
    //输入输出上述几个函数中已经介绍过,变换过程为:先得出P点在相机坐标系下的表示,然后再变换到世界坐标系中即可
    Vector3d Camera::pixel2world ( const Vector2d& p_p, const SE3& T_c_w, double depth )
    {
        return camera2world ( pixel2camera ( p_p, depth ), T_c_w );
    }
    
  2. Frame类:定义了ID,时间戳,位姿,相机和图像(color和depth)
    在帧类中需要注意的点为
    1. 设置了一个静态变量,与类存活时间一致,从而可以保证先后加入的帧的id按序增加
       Frame::Ptr Frame::createFrame()
       {
           static long factory_id = 0;
           return Frame::Ptr( new Frame(factory_id++) );
       }
    
    1. 在findDepth(…)函数中,有一个之前一直强调的点。即对于像素位置x,y处的深度值,应该是访问depth图中第y行的第x个坐标的值
    int x = cvRound(kp.pt.x);
    int y = cvRound(kp.pt.y);
    ushort d = depth_.ptr<ushort>(y)[x];
    
  3. MapPoint类:有ID,在世界坐标系中的位置,可视化方向的法向量,匹配描述符,被观察的次数和被匹配的次数
  4. Map类:Map类用于管理关键帧和地图点,所以在该类中具有上述两个类类型的unoreded_map的成员变量。每次插入对应值时,只需要首先判断是否已在Map中,若不在,则插入。因为每个帧/地图点的id是唯一的,所以以id为key值,对应的具体的帧/地图点为value