《视觉 SLAM 十四讲》V2 第 11 讲 回环检测【消除累积误差】

news2024/11/26 11:54:00

待做:

  • 习题整理
  • 相关文献【新的综述】等

P283

在这里插入图片描述

文章目录

    • 11.2 词袋 模型
      • 11.3.2 Code: 创建字典
      • 11.4.2 Code: 相似度 计算
        • 训练 自己的字典 报错
    • 习题
      • √ 题1
      • √ 题2
      • 题3 DBoW3库
      • 题4
      • 题5

基于 词袋 的外观式 回环检测

SLAM主体(前端后端): 估计相机运动
前端: 提供特征点的提取 和 轨迹、地图的初值
后端: 对所有这些数据进行优化

视觉里程计 仅考虑相邻时间上 的 关键帧。

累积误差

全局一致 的 轨迹和地图

回环检测的关键: 如何有效地 检测出 相机经过同一个地方 这件事。

位姿图 质点 弹簧系统。提高了系统稳定性。

回环边: 把带有累计误差的边 “拉” 到了正确的位置。

估计的轨迹和地图 在长时间下 的正确性
利用回环检测 进行 重定位

视觉里程计: 仅有前端 和 局部后端的系统
SLAM: 带有回环检测和全局后端的系统

1、对任意两幅图像都做一遍特征匹配

  • 不是所有图像都有回环
  • 对于 N 对可能的回环, 要检测 C 2 N C_2^N C2N 次,复杂度为 O ( N 2 ) O(N^2) O(N2)
  • 无法实时

2、随机抽取历史数据进行回环检测

  • 检测效率不高

3、基于 外观 ✔📌

4、室外 GPS

如何 计算图像间的相似性
不选择 两幅图像相减 s ( A , B ) = ∣ ∣ A − B ∣ ∣ s(\bm{A, B}) = ||\bm{A-B}|| s(A,B)=∣∣AB∣∣ 比较相似性 的原因:
1、像素灰度受环境光照和相机曝光的影响
2、相机视角变化,会使得像素在图像中发生位移,造成大的差异值

感知偏差(Perceptual Aliasing) 假阳性(False Positive)
感知变异(Perceptual Variability) 假阴性 (False Negative)

准确率:Precision = T P T P + F P \frac{TP}{TP+FP} TP+FPTP 判为正的正样本数/ 判为正的样本数
召回率:Recall = T P T P + F N \frac{TP}{TP+FN} TP+FNTP 判为正的正样本数/ 全部正样本数

在这里插入图片描述

准确率: 算法提取的所有回环中 确实是 真实回环 的概率。
召回率: 在所有真实回环中 被正确检测出来的概率。

A 在 准确率 较高时 还有很好的召回率, B在 70% 召回率 的情况下还能保证 较好的准确率。

SLAM : 准确率 要求更高

  • 检测结果是 而实际不是 【假阳性】 添加错误的边有可能 导致 整个建图失效

召回率 低些 ——> 部分回环 没被检测到 ——> 累积误差 影响建图

  • 一两次 回环即可完全消除。

特征匹配: 费时、光照变化会导致特征描述不稳定。

11.2 词袋 模型

Bag-of-Words(Bow) : “图像上有哪几种特征” 来描述一幅图像。

是否出现

强调的是 Words 的有无, 无关顺序。

字典生成 聚类
K-means
在这里插入图片描述
把已经提取的大量特征点 聚类成 一个含有 k k k 个单词的字典。

如何 根据图像中某个特征点查找字典中相应的单词

在这里插入图片描述
在这里插入图片描述

11.3.2 Code: 创建字典

ORB 特征描述

  • ORB(Oriented FAST and Rotated BRIEF)特征

对10张 目标图像 提取 ORB特征 并存放至 vector 容器中,然后调用 DBoW3的字典生成接口。
在这里插入图片描述

————————配置环境: 开始
1、下载 DBow3

git clone https://github.com/rmsalinas/DBow3.git

2、进入 文件夹,并打开命令行窗口在这里插入图片描述
3、按照 cmake 流程进行编译安装

mkdir build && cd build
cmake ..
make 
sudo make install

OpenCV版本查看

python3 -c "import cv2; print(cv2.__version__)"

4.2.0

查看绝对路径
在这里插入图片描述

报错:


在这里插入图片描述
CMakeLists.txt修改
在这里插入图片描述

feature_training.cpp修改
在这里插入图片描述
这里顺便也改了。。
在这里插入图片描述

修改后 务必记得 cmake 一遍

cd build
cmake ..
make 
./feature_training

在这里插入图片描述

————————配置环境: 结束
feature_training.cpp

#include "DBoW3/DBoW3.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <iostream>
#include <vector>
#include <string>

using namespace cv;
using namespace std;

/***************************************************
 * 本节演示了如何根据data/目录下的十张图训练字典
 * ************************************************/

int main( int argc, char** argv ) {
    // read the image 
    cout<<"reading images... "<<endl;
    vector<Mat> images; 
    for ( int i=0; i<10; i++ )
    {
        string path = "../data/"+to_string(i+1)+".png";
        images.push_back( imread(path) );
    }
    // detect ORB features
    cout<<"detecting ORB features ... "<<endl;
    Ptr< Feature2D > detector = ORB::create();
    vector<Mat> descriptors;
    for ( Mat& image:images )
    {
        vector<KeyPoint> keypoints; 
        Mat descriptor;
        detector->detectAndCompute( image, Mat(), keypoints, descriptor );
        descriptors.push_back( descriptor );
    }
    
    // create vocabulary 
    cout<<"creating vocabulary ... "<<endl;
    DBoW3::Vocabulary vocab;
    vocab.create( descriptors );
    cout<<"vocabulary info: "<<vocab<<endl;
    vocab.save( "vocabulary.yml.gz" );
    cout<<"done"<<endl;
    
    return 0;
}

CMakeLists.txt

cmake_minimum_required( VERSION 2.8 )
project( loop_closure )

set( CMAKE_BUILD_TYPE "Release" )
set( CMAKE_CXX_FLAGS "-std=c++11 -O3" )

# opencv 
find_package( OpenCV 4.2.0 REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )

# dbow3 
# dbow3 is a simple lib so I assume you installed it in default directory 
set( DBoW3_INCLUDE_DIRS "/usr/local/include" )
set( DBoW3_LIBS "/usr/local/lib/libDBoW3.so" )

add_executable( feature_training feature_training.cpp )
target_link_libraries( feature_training ${OpenCV_LIBS} ${DBoW3_LIBS} )

add_executable( loop_closure loop_closure.cpp )
target_link_libraries( loop_closure ${OpenCV_LIBS} ${DBoW3_LIBS} )

add_executable( gen_vocab gen_vocab_large.cpp )
target_link_libraries( gen_vocab ${OpenCV_LIBS} ${DBoW3_LIBS} )

11.4.2 Code: 相似度 计算

TF-IDF (Term Frequency-Inverse Document Frequency)
频率-逆文档频率

在这里插入图片描述
某单词在字典中 出现的频率越低,分类图像时 区分度越高。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

使用上节的字典生成词袋 并 比较差异
要改动的地方: 之前的data路径要是没改记得改
在这里插入图片描述
要是改了要 cmake 一遍

./loop_closure

在这里插入图片描述
loop_closure.cpp

#include "DBoW3/DBoW3.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <iostream>
#include <vector>
#include <string>

using namespace cv;
using namespace std;

/***************************************************
 * 本节演示了如何根据前面训练的字典计算相似性评分
 * ************************************************/
int main(int argc, char **argv) {
    // read the images and database  
    cout << "reading database" << endl;
    DBoW3::Vocabulary vocab("./vocabulary.yml.gz");
    // DBoW3::Vocabulary vocab("./vocab_larger.yml.gz");  // use large vocab if you want: 
    if (vocab.empty()) {
        cerr << "Vocabulary does not exist." << endl;
        return 1;
    }
    cout << "reading images... " << endl;
    vector<Mat> images;
    for (int i = 0; i < 10; i++) {
        string path = "../data/" + to_string(i + 1) + ".png";
        images.push_back(imread(path));
    }

    // NOTE: in this case we are comparing images with a vocabulary generated by themselves, this may lead to overfit.
    // detect ORB features
    cout << "detecting ORB features ... " << endl;
    Ptr<Feature2D> detector = ORB::create();
    vector<Mat> descriptors;
    for (Mat &image:images) {
        vector<KeyPoint> keypoints;
        Mat descriptor;
        detector->detectAndCompute(image, Mat(), keypoints, descriptor);
        descriptors.push_back(descriptor);
    }

    // we can compare the images directly or we can compare one image to a database 
    // images :
    cout << "comparing images with images " << endl;
    for (int i = 0; i < images.size(); i++) {
        DBoW3::BowVector v1;
        vocab.transform(descriptors[i], v1);
        for (int j = i; j < images.size(); j++) {
            DBoW3::BowVector v2;
            vocab.transform(descriptors[j], v2);
            double score = vocab.score(v1, v2);
            cout << "image " << i << " vs image " << j << " : " << score << endl;
        }
        cout << endl;
    }

    // or with database 
    cout << "comparing images with database " << endl;
    DBoW3::Database db(vocab, false, 0);
    for (int i = 0; i < descriptors.size(); i++)
        db.add(descriptors[i]);
    cout << "database info: " << db << endl;
    for (int i = 0; i < descriptors.size(); i++) {
        DBoW3::QueryResults ret;
        db.query(descriptors[i], ret, 4);      // max result=4
        cout << "searching for image " << i << " returns " << ret << endl << endl;
    }
    cout << "done." << endl;
}

11.5.1
修改这里 并重新 cmake 即可

在这里插入图片描述

./loop_closure

在这里插入图片描述

把相近的回环聚成 一类。比如 第n, n-2, n-3帧

检测之后的验证:
1、回环 缓存【多次检测到相似✔】: 一段时间中一直检测到的回环,才是正确的回环
2、回环检测到的帧进行特征匹配【相应 相机位姿也匹配✔】,估计各自的相机运动,检查位姿是否出入很大。

分类
图像相似性

训练 自己的字典 报错

在这里插入图片描述
参考这里
1、
gen_vocab_large.cpp

#include "DBoW3/DBoW3.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <iostream>
#include <vector>
#include <string>

using namespace cv;
using namespace std;


int main( int argc, char** argv )
{
    string dataset_dir = argv[1];
    ifstream fin ( dataset_dir+"/associate.txt" );
    if ( !fin )
    {
        cout<<"please generate the associate file called associate.txt!"<<endl;
        return 1;
    }

    vector<string> rgb_files, depth_files;
    vector<double> rgb_times, depth_times;
    while ( !fin.eof() )
    {
        string rgb_time, rgb_file, depth_time, depth_file;
        fin>>rgb_time>>rgb_file>>depth_time>>depth_file;
        rgb_times.push_back ( atof ( rgb_time.c_str() ) );
        depth_times.push_back ( atof ( depth_time.c_str() ) );
        rgb_files.push_back ( dataset_dir+"/"+rgb_file );
        depth_files.push_back ( dataset_dir+"/"+depth_file );

        if ( fin.good() == false )
            break;
    }
    fin.close();
    
    cout<<"generating features ... "<<endl;
    vector<Mat> descriptors;
    Ptr< Feature2D > detector = ORB::create();
    int index = 1;
    for ( string rgb_file:rgb_files )
    {
        Mat image = imread(rgb_file);
        vector<KeyPoint> keypoints; 
        Mat descriptor;
        detector->detectAndCompute( image, Mat(), keypoints, descriptor );
        descriptors.push_back( descriptor );
        cout<<"extracting features from image " << index++ <<endl;
    }
    cout<<"extract total "<<descriptors.size()*500<<" features."<<endl;
    
    // create vocabulary 
    cout<<"creating vocabulary, please wait ... "<<endl;
    DBoW3::Vocabulary vocab;
    vocab.create( descriptors );
    cout<<"vocabulary info: "<<vocab<<endl;
    vocab.save( "vocab_larger.yml.gz" );
    cout<<"done"<<endl;
    
    return 0;
}

习题

在这里插入图片描述

√ 题1

sklearn 分类 评估指标
在这里插入图片描述
PR曲线

pip install -U scikit-learn

sklearn.metrics.PrecisionRecallDisplay
test.py

import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.metrics import PrecisionRecallDisplay
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

X, y = make_classification(random_state=0)
X_train, X_test, y_train, y_test = train_test_split(
        X, y, random_state=0)
clf = LogisticRegression()  # 分类模型  
clf.fit(X_train, y_train) 
y_pred = clf.predict_proba(X_test)[:, 1]  # 得到预测值

# 绘制 PR 曲线  需要预测结果  及  label
PrecisionRecallDisplay.from_predictions(
   y_test, y_pred)
plt.show()

python3 test.py

在这里插入图片描述

√ 题2

2、验证回环检测算法,需要有人工标记回环的数据集。然而人工标记回环是很不方便的,我们会考虑根据标准轨迹计算回环。即,如果轨迹中有两个帧的位姿非常相近,就认为它们是回环。请根据TUM数据集给出的标准轨迹,计算出一个数据集中的回环。这些回环的图像真的相似吗?

解答链接

在这里插入图片描述
FAB-MAP: Probabilistic Localization and Mapping in the Space of Appearance

题3 DBoW3库

DBoW3是DBow2库的改进版本,DBow2库是一个开源c++库,用于索引图像并将其转换为词袋表示。它实现了一个层次树,用于在图像特征空间中逼近最近邻,并创建视觉词汇表。DBoW3还实现了一个图像数据库,其中包含反向和直接文件,用于索引图像,并支持快速查询和特性比较。

github链接

git clone https://github.com/rmsalinas/DBoW3.git

可参考
————————————————

题4

4、
1、欧几里得距离(Eucledian Distance)
在这里插入图片描述

2、曼哈顿距离(Manhattan Distance)
3、明可夫斯基距离(Minkowski distance)
在这里插入图片描述

在这里插入图片描述

4、(余弦相似度)Cosine Similarity 方向

5、Jaccard Similarity
在这里插入图片描述

六、皮尔森相关系数(Pearson Correlation Coefficient)
在这里插入图片描述

——————————————————

题5

5、Chow-Liu树:
链接1: https://web.stanford.edu/class/ee376a/files/2017-18/chow-liu.pdf
链接2【详细】:https://people.kth.se/~tjtkoski/chowliulect.pdf

Chow-Liu树是对概率分布的“最佳可能”树形信念网络逼近,使得所有边都远离根。利用真实分布与Chow-Liu树定义的分布之间的Kullback-Leibler距离来测量近似的质量。当我们从数据中学习时,“真实”分布是由观测值的频率定义的。Chow和Liu(1968)表明,最优树可以作为所有变量上的最大权值生成树,其中每条边的权值作为由边连接的变量之间的互信息给出。
Chow-Liu树可以构造如下:
1、为每一对 ( X i , X j ) (X_i, X_j) (Xi,Xj) 计算互信息 M I ( X i , X j ) MI(X_i, X_j) MI(Xi,Xj)
2、考虑完全 M I MI MI加权图, 无向。
3、为完全 M I MI MI加权图构建最大权值生成树。
4、通过选择任何变量作为根,并将链接的方向设置为从它向外,来指导生成的树。

在这里插入图片描述
Chow-Liu树代码实现Python

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1049282.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图片处理后再保存为图片到文件夹中,文件夹下文件名不变改格式保存

首先读取图片&#xff1b; 然后处理&#xff0c;得到cv:Mat类型&#xff1b; 对cv:Mat类型图片写入文件夹&#xff0c;保存到指定路径。 像raw图等不能直接读取显示&#xff0c;需要先进行解码&#xff0c;转换为可以显示的图片。 下面举例读入本来可以显示的图。以下代码加…

哈弗猛龙实力登场,「方盒子猛改派对」掀起越野改装新热潮

9月22日-24日&#xff0c;哈弗猛龙“方盒子猛改派对”在北京751 D-PARK 火车头广场成功举办。活动现场盛况空前&#xff0c;不仅有官方展出的11台不同风格的猛改车型&#xff0c;更吸引了不同领域的博主大咖及越野达人前来参与活动。 与此同时&#xff0c;哈弗猛龙用户大定权益…

【EI会议征稿】第三届信号处理与通信技术国际学术会议(SPCT 2023)

第三届信号处理与通信技术国际学术会议&#xff08;SPCT 2023&#xff09; 2023 3rd International Conference on Signal Processing and Communication Technology 第三届信号处理与通信技术国际学术会议&#xff08;SPCT 2023&#xff09;将于2023年12月1-3日在长春召开。S…

【AIPOD案例操作教程】斜流风扇轮毂优化

AIPOD是由天洑软件自主研发的一款通用的智能优化设计软件&#xff0c;致力于解决能耗更少、成本更低、重量更轻、散热更好、速度更快等目标的工程设计寻优问题。针对工业设计领域的自动化程度低、数值模拟计算成本高等痛点&#xff0c;基于人工智能技术、自研先进的智能代理学习…

MySQL存储引擎以及InnoDB、MyISAM、Memory特点介绍

存储引擎介绍和基本使用 基本介绍&#xff1a; 存储引擎是数据库的核心&#xff0c;存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式 。存储引擎是基于表的&#xff0c;而不是基于库的&#xff0c;所以存储引擎也可被称为表类型。我们可以在创建表的时候&…

U盘植马之基于arduino的badusb实现及思考

引言 曾经有这么一段传说&#xff0c;在某次攻防演练时&#xff0c;某攻击队准备了一口袋U盘前往了目标单位的工作园区&#xff0c;在园区围墙外停下了脚步&#xff0c;然后开始不停扔U盘进去&#xff0c;最后发现有大量的“猎奇者”上线。 U盘植马是常见的近源渗透方式之一&am…

若依不分离+Thymeleaf select选中多个回显

项目中遇到的场景&#xff0c;亲测实用 表单添加时&#xff0c;select选中多个&#xff0c;编辑表单时&#xff0c;select多选回显&#xff0c;如图 代码&#xff1a; // 新增代码 <label class"col-sm-3 control-label">通道&#xff1a;</label><…

再学C++ | std::set 的原理

std::set 是C标准库中的容器之一&#xff0c;它基于红黑树实现。std::set 利用红黑树的特性来实现有序的插入、查找和删除操作&#xff0c;并且具有较好的平均和最坏情况下的时间复杂度。 当向 std::set 插入元素时&#xff0c;它会按照特定的比较函数&#xff08;bool less<…

软件可靠性基础

软件可靠性基础 软件可靠性基本概念串并联系统可靠性计算软件可靠性测试软件可靠性建模软件可靠性管理软件可靠性设计容错&#xff0c;检错的技术 选择题考基本概念&#xff08;MTBF&#xff09;&#xff0c;很少考 非重点 软件可靠性基本概念 这个章节中&#xff0c;第一个…

Leetcode算法题练习(一)

目录 一、前言 二、移动零 三、复写零 四、快乐数 五、电话号码的字母组合 六、字符串相加 一、前言 大家好&#xff0c;我是dbln&#xff0c;从本篇文章开始我就会记录我在练习算法题时的思路和想法。如果有错误&#xff0c;还请大家指出&#xff0c;帮助我进步。谢谢&…

2023-9-27 JZ55 二叉树的深度

题目链接&#xff1a;二叉树的深度 import java.util.*; /** public class TreeNode {int val 0;TreeNode left null;TreeNode right null;public TreeNode(int val) {this.val val;}} */ public class Solution {public int TreeDepth(TreeNode root) {if(root null) ret…

续航605km,价格 11.77 万起带激光雷达,你卷我也卷

9 月 21 日&#xff0c;睿蓝 7 正式上市&#xff0c;新车提供 6 款车型&#xff0c;售价区间 11.77-17.37 万元。 权益方面&#xff0c;提供 701 元订金抵 2000 元车款、2000 元选装基金、终身 24 小时救援服务、10 万 3 年 0 息金融政策、3000 元置换/ 1000 元增购补贴、6 年/…

【Java 进阶篇】MySQL主键约束详解

MySQL是一个强大的关系型数据库管理系统&#xff0c;用于存储和管理大量数据。在数据库中&#xff0c;主键约束是一项非常重要的概念&#xff0c;它有助于确保数据的完整性和唯一性。本文将详细介绍MySQL主键约束&#xff0c;包括什么是主键、为什么需要主键、如何创建主键以及…

自增自减运算符i++与++i的区别

自增自减运算符用作前缀与用作后缀时略有不同。 i和i的区别&#xff1a; 1、i 返回原来的值&#xff0c;i 返回加1后的值。&#xff08; a i 是先给 a 赋值&#xff0c;然后 i 再自增&#xff1b;a i是 i 先自增&#xff0c;然后给 a 赋值。&#xff09; #include<iost…

(2023|ICLR,检索引导,交叉引导,EntityDrawBench)Re-Imagen:检索增强的文本到图像生成器

Re-Imagen: Retrieval-augmented text-to-image generator 公众号&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 1. 简介 2. 相关工作 3. 模型 3.1 预备知识 3.2 用多模态知识…

msvcp140.dll丢失的解决方法与msvcp140.dll是什么东西详细解析

在使用电脑时&#xff0c;可能会遇到打开软件时提示“找不到 msvcp140.dll&#xff0c;无法继续执行代码”的问题。这通常意味着你的计算机上缺少 Microsoft Visual C Redistributable 的运行时库&#xff0c;或者该库的版本不正确。下面是我找了几天的修复方法&#xff0c;今天…

PBR的应用

项目拓扑与项目需求 项目需求&#xff1a;某企业网络拥有三个出口&#xff0c;分别使用AR1、AR2、AR3链接运营商网络。其中AR1为万兆出口&#xff0c;而AR2、AR3为千兆出口。现在需要实现以下需求&#xff1a; 希望vlan10的流量能够强制通过AR1作为业务的出口&#xff0c;vla…

iCloud邮箱怎么登录?看这里,2招教你搞定!

iCloud邮箱是苹果公司推出的一款功能强大的邮件服务。通过iCloud邮箱&#xff0c;用户可以实现接收和发送电子邮件。苹果强调保护用户的隐私和数据安全&#xff0c;所以icloud邮箱为用户提供了高度保密的邮件加密服务&#xff0c;能够确保用户的邮件在传输时得到保护。 但是&a…

Kotlin语言基础(三)- 函数

函数可以定义特定功能的代码块。 一、函数定义 Kotlin语言定义函数的基本形式&#xff1a; fun 函数名(【参数&#xff1a;参数类型,参数&#xff1a;参数类型…】)【:返回值类型】{ //函数体 } 如果函数体只有一条返回值&#xff0c;也可以简化成如下形式&#xff1a; fun 函…

springboot实现ACL+RBAC权限体系

本文基于web系统的权限控制非常重要的前提下&#xff0c;从ALC和RBAC权限控制两个方面&#xff0c;介绍如何在springboot项目中实现一个完整的权限体系。 源码下载 &#xff1a;https://gitee.com/skyblue0678/springboot-demo 序章 一个后台管理系统&#xff0c;基本都有一套…