【SLAM】视觉SLAM系统设计与未来研究探讨

本文总结了视觉SLAM基础知识,介绍了SLAM系统的四大组成部分:前端估计、后端优化、回环检测和地图重建。并通过双目摄像头实现了一个完整的SLAM系统。未来发展方向包括多传感器融合、机器人知识库构建、云计算机器人以及SLAM与深度学习的融合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.前言

经过漫长的SLAM系列文章更新,视觉SLAM基础入门与学习部分进入最后一章,这一章,我会总结一下之前讲过的各个部分的基础知识,并带领大家完成一个完整SLAM系统的设计并展望一下未来的研究方向。

首先,依然带给大家来自百度百科关于SLAM的严格定义:

> SLAM (simultaneous localization and mapping),也称为CML (Concurrent Mapping and Localization), 即时定位与地图构建,或并发建图与定位。问题可以描述为:将一个机器人放入未知环境中的未知位置,是否有办法让机器人一边移动一边逐步描绘出此环境完全的地图,所谓完全的地图(a consistent map)是指不受障碍行进到房间可进入的每个角落。

依据大多数的研究定义,通常把SLAM分为4大部分:

  1. 前端估计
  2. 后端优化
  3. 回环检测
  4. 地图重建
  • 前端估计,又称,前端跟踪、帧间估计等;
  • 后端优化,又称,后端估计等;
  • 回环检测,又称,重定位、场景识别等;
  • 地图重建,又称,地图构建等。

2.系统

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x7scL8to-1590474971425)(https://b02.ickimg.com/202005/582f29f930de257ce460cb0432b6afe8.png)]

一个完整的SLAM系统由以上这4部分组成,其中:前端估计,我们从传感器、特征点、特征提取、特征匹配、重投影、李群李代数、旋转矩阵和平移矩阵等部分进行了讲解;后端优化,我们从BA优化、最小二乘法、梯度法、牛顿法、卡尔曼滤波等部分进行了讲解说明;回环检测,我们从图优化、词袋法、字典法等部分进行了讲解;地图重建、我们从位姿地图、八叉树地图、单目建图等部分进行了讲解。

SLAM系统复杂、内容众多,学习门槛较大、难度较高。

希望这些讲解可以为大家打开SLAM的大门。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PfblQuxY-1590474971432)(https://b05.ickimg.com/202005/970f3ebc331653e24b8fc597759ba565.png)]

3.实现

这里我会带领大家通过双目摄像头实现一个完整的SLAM系统。

首先,如下为相关的设计参数、接口等:


namespace myslam {

// forward declare
struct MapPoint;
struct Feature;

/@@**
 ** 每一帧分配独立id,关键帧分配关键帧ID
 */
struct Frame {
   public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
    typedef std::shared_ptr Ptr;

    unsigned long id_ = 0;           // id of this frame
    unsigned long keyframe_id_ = 0;  // id of key frame
    bool is_keyframe_ = false;       // 是否为关键帧
    double time_stamp_;              // 时间戳,暂不使用
    SE3 pose_;                       // Tcw 形式Pose
    std::mutex pose_mutex_;          // Pose数据锁
    cv::Mat left_img_, right_img_;   // stereo images

    // extracted features in left image
    std::vector<std::shared_ptr<feature>&gt; features_left_;
    // corresponding features in right image, set to nullptr if no corresponding
    std::vector<std::shared_ptr<feature>&gt; features_right_;

   public:  // data members
    Frame() {}

    Frame(long id, double time_stamp, const SE3 &amp;pose, const Mat &amp;left,
          const Mat &amp;right);

    // set and get pose, thread safe
    SE3 Pose() {
        std::unique_lock<std::mutex> lck(pose_mutex_);
        return pose_;
    }

    void SetPose(const SE3 &amp;pose) {
        std::unique_lock<std::mutex> lck(pose_mutex_);
        pose_ = pose;
    }

    /// 设置关键帧并分配并键帧id
    void SetKeyFrame();

    /// 工厂构建模式,分配id 
    static std::shared_ptr CreateFrame();
};

}  // namespace myslam

#endif  // MYSLAM_FRAME_H

如下,是特征提取的部分以及关于特征点的部分:


namespace myslam {

struct Frame;
struct MapPoint;

/@@**
 * 2D 特征点
 * 在三角化之后会被关联一个地图点
 */
struct Feature {
   public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
    typedef std::shared_ptr<feature> Ptr;

    std::weak_ptr frame_;         // 持有该feature的frame
    cv::KeyPoint position_;              // 2D提取位置
    std::weak_ptr<mappoint> map_point_;  // 关联地图点

    bool is_outlier_ = false;       // 是否为异常点
    bool is_on_left_image_ = true;  // 标识是否提在左图,false为右图

   public:
    Feature() {}

    Feature(std::shared_ptr frame, const cv::KeyPoint &amp;kp)
        : frame_(frame), position_(kp) {}
};
}  // namespace myslam

#endif  // MYSLAM_FEATURE_H

其次,如下是关于图像三维点的部分:


/@@**
 * 路标点类
 * 特征点在三角化之后形成路标点
 */
struct MapPoint {
   public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
    typedef std::shared_ptr<mappoint> Ptr;
    unsigned long id_ = 0;  // ID
    bool is_outlier_ = false;
    Vec3 pos_ = Vec3::Zero();  // Position in world
    std::mutex data_mutex_;
    int observed_times_ = 0;  // being observed by feature matching algo.
    std::list<std::weak_ptr<feature>&gt; observations_;

    MapPoint() {}

    MapPoint(long id, Vec3 position);

    Vec3 Pos() {
        std::unique_lock<std::mutex> lck(data_mutex_);
        return pos_;
    }

    void SetPos(const Vec3 &amp;pos) {
        std::unique_lock<std::mutex> lck(data_mutex_);
        pos_ = pos;
    };

    void AddObservation(std::shared_ptr<feature> feature) {
        std::unique_lock<std::mutex> lck(data_mutex_);
        observations_.push_back(feature);
        observed_times_++;
    }

    void RemoveObservation(std::shared_ptr<feature> feat);

    std::list<std::weak_ptr<feature>&gt; GetObs() {
        std::unique_lock<std::mutex> lck(data_mutex_);
        return observations_;
    }

    // factory function
    static MapPoint::Ptr CreateNewMappoint();
};
}  // namespace myslam

#endif  // MYSLAM_MAPPOINT_H

如下,是对所有地图相关的代码:


class Map {
   public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
    typedef std::shared_ptr<map> Ptr;
    typedef std::unordered_map<unsigned long,="" mappoint::ptr=""> LandmarksType;
    typedef std::unordered_map<unsigned long,="" frame::ptr=""> KeyframesType;

    Map() {}

    /// 增加一个关键帧
    void InsertKeyFrame(Frame::Ptr frame);
    /// 增加一个地图顶点
    void InsertMapPoint(MapPoint::Ptr map_point);

    /// 获取所有地图点
    LandmarksType GetAllMapPoints() {
        std::unique_lock<std::mutex> lck(data_mutex_);
        return landmarks_;
    }
    /// 获取所有关键帧
    KeyframesType GetAllKeyFrames() {
        std::unique_lock<std::mutex> lck(data_mutex_);
        return keyframes_;
    }

    /// 获取激活地图点
    LandmarksType GetActiveMapPoints() {
        std::unique_lock<std::mutex> lck(data_mutex_);
        return active_landmarks_;
    }

    /// 获取激活关键帧
    KeyframesType GetActiveKeyFrames() {
        std::unique_lock<std::mutex> lck(data_mutex_);
        return active_keyframes_;
    }

    /// 清理map中观测数量为零的点
    void CleanMap();

   private:
    // 将旧的关键帧置为不活跃状态
    void RemoveOldKeyframe();

    std::mutex data_mutex_;
    LandmarksType landmarks_;         // all landmarks
    LandmarksType active_landmarks_;  // active landmarks
    KeyframesType keyframes_;         // all key-frames
    KeyframesType active_keyframes_;  // all key-frames

    Frame::Ptr current_frame_ = nullptr;

    // settings
    int num_active_keyframes_ = 7;  // 激活的关键帧数量
};
}  // namespace myslam


简单介绍一些逻辑:

双目的立体匹配用来提取三维特征点;
左通道用来估计光流,右通道连续帧间不使用;
光流估计的特征点较少的时候,为关键帧。

4.未来

视觉slam未来的发展方向主要集中在传感器的多传感器融合、机器人的庞大知识、,云计算机器人、slam和深度学习的相关融合方向上。其中多传感器融合的数据处理是目前SLAM当中常用的一种传感器数据融合方式,因为传统的slam传感器有于传感器的限制,导致其数据维度和感知并不是很强,通过多传感器融合可以达到强大的环境感知,提高机器人的感知能力。

对于机器人的知识库,我们可以让机器人完成更多的内容,通过slam的构建,对环境进行感知,构建惊人庞大知识库。其次,由于影响及机器人实时运作的主要关系是机器人的控制系统,但是当我们将机器人的控制放在云端服务器的时候,这样我们就可以使机器人的实时性更加良好,其中就包含了云计算机器人。

随着云技术的发展,云计算机器人将成一个热门的研究方向。除此之外,slam和深度学习的融合也成为发展方向,因为深度学习在传统的图像领域表现良好,但是在slam应用当中依然有很多缺陷和很多不足,所以现在这也是一个很大的热门方向。

5.总结

首先感谢大家阅读SLAM这一系列的文章,这一个系列目标就是SLAM的基础讲解与入门,当然,由于时间较短和内容众多,文章还是有很多的不足,希望大家可以在留言区批评指正、多多交流。

除此之外呢,首先感谢高翔的《视觉slam14讲》,作为视觉slam的在国内为数不多的基础教材,为很多slam基础研究者提供了基础学习的书籍。其次,要感谢很多开源社区提供一些代码以供大家学习。希望大家在后续学习当中可以将自己的研究成果和代码开源出来,以供大家学习,共同促进SLAM的发展与进步。

> 参考资料:《视觉SLAM十四讲》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值