视觉SLAM--回环检测

文章目录

  • 创建字典
  • 相似度计算
  • 增加字典规模

回环检测的意义:可以使 后端位姿图得到一个 全局一致估计。
视觉SLAM的主流做法: 基于外观的回环检测方法,仅 根据两幅图像的相似性确定回环检测关系。这种方法,摆脱了累计误差,使得回环检测模块可以称为SLAM系统中相对独立的模块。

创建字典

词袋,Bag-of-Words(BoW),目的是用"图像上有哪几种特征"来描述一幅图像。

ch11\feature_training.cpp

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 featurescout<<"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;
}

相似度计算

ch11\loop_closure.cpp

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 featurescout << "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=4cout << "searching for image " << i << " returns " << ret << endl << endl;}cout << "done." << endl;
}

增加字典规模

ch11\gen_vocab_large.cpp

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、书籍:《视觉SLAM十四讲:从理论到实践(第2版)》
2、代码:https://github.com/gaoxiang12/slambook2

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

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

相关文章

分类损失函数 (一) torch.nn.CrossEntropyLoss()

1、交叉熵 是一种用于衡量两个概率分布之间的距离或相似性的度量方法。机器学习中&#xff0c;交叉熵常用于损失函数&#xff0c;用于评估模型的预测结果和实际标签的差异。公式&#xff1a; y&#xff1a;真是标签的概率分布&#xff0c;y&#xff1a;模型预测的概率分布 …

数据库中的内、外、左、右连接

常用的数据库连表形式&#xff1a; 内连接 &#xff1a;inner join 外连接 &#xff1a;outer join 左外连接 &#xff1a;left outer join 左连接 &#xff1a;left join 右外连接 right outer join 右连接&#xff1a; right join 全连接 full join 、union 一、内连接 内…

企业私有云的部署都有哪些方式?

如今常见的企业私有云的部署方式有自建私有云、托管私有云、虚拟私有云、混合云、容器化私有云、本地数据中心部署等。如今&#xff0c;企业私有云的部署呈多样化趋势&#xff0c;以用来满足各个企业的具体需求。以下是RAK部落小编为大家汇总的企业私有云常见的部署方式&#x…

LeetCode 58.最后一个单词的长度 C++

LeetCode 58.最后一个单词的长度 C 思路&#x1f914;&#xff1a; 先解决当最后字符为空格的情况&#xff0c;如果最后字符为空格下标就往后移动&#xff0c;直到不为空格才停止&#xff0c;然后用rfind查询空格找到的就是最后一个单词的起始位置&#xff0c;最后相减就是单词…

flowable执行监听器动态指定审批人在退回时产生的bug

场景&#xff1a; 退回产生的bug&#xff0c;有一个结点&#xff0c;本身是通过执行监听器判断上一个结点的审批人来得到这个结点的审批人。之前是通过直接的获取最新task来拿到&#xff0c;但是在退回场景下&#xff0c;最新task为退回结点&#xff0c;故产生错误。 解决&…

C++ 正则库与HTTP请求

正则表达式的概念和语法 用于描述和匹配字符串的工具&#xff0c;通过特定的语法规则&#xff0c;灵活的定义复杂字符串匹配条件 常用语法总结 基本字符匹配 a&#xff1a;匹配字符aabc&#xff1a;匹配字符串abc 元字符&#xff08;特殊含义的字符&#xff09; .&#xff1a;匹…

stable diffusion webui环境配置遇到的问题

环境配置步骤&#xff1a; conda创建一个python3.10的环境&#xff0c;起个名叫sdenv, 使用命令conda create -n denv python3.10进入创建好的环境在webui的路径下直接运行python launch.py会自动开始安装所需的包&#xff08;可能需要梯子或者在系统配置中添加pip的国内源&am…

1Panel面板配置java运行环境及网站的详细操作教程

本篇文章主要讲解&#xff0c;通过1Panel面板实现java运行环境&#xff0c;部署网站并加载的详细教程。 日期&#xff1a;2024年7月21日 作者&#xff1a;任聪聪 独立博客&#xff1a;https://rccblogs.com/501.html 一、实际效果 二、详细操作 步骤一、给我的项目进行打包&am…

在jsPsych中使用Vue

jspsych 介绍 jsPsych是一个非常好用的心理学实验插件&#xff0c;可以用来构建心理学实验。具体的就不多介绍了&#xff0c;大家可以去看官网&#xff1a;https://www.jspsych.org/latest/ 但是大家在使用时就会发现&#xff0c;这个插件只能使用js绘制界面&#xff0c;或者…

陌陌聊天数据案例分析

目录 背景介绍和需求分析基于hive数仓实现需求开发根据聊天数据建库建表加载数据ETL数据清洗背景分析原始数据出现的问题ETL实现 需求指标统计思路需求开发 基于FineBI实现可视化报表配置流程构建可视化报表 总结 背景介绍和需求分析 陌陌是一个聊天平台&#xff0c;每天都会产…

不能包含中文的正则表达式

原文 1、不包含汉字[^\u4e00-\u9fa5] var r /^[^\u4e00-\u9fa5]$/ if(r.test(str)){} 2、只能包含汉字 [\u4e00-\u9fa5]

STM32自己从零开始实操10:PCB全过程

一、PCB总体分布 分布主要参考有&#xff1a; 方便供电布线。方便布信号线。方便接口。人体工学。 以下只能让大家看到各个模块大致分布在板子的哪一块&#xff0c;只能说每个人画都有自己的理由&#xff0c;我的理由如下。 还有很多没有表达出来的东西&#xff0c;我也不知…

二叉树---二叉搜索树中的众数

题目&#xff1a; 给你一个含重复值的二叉搜索树&#xff08;BST&#xff09;的根节点 root &#xff0c;找出并返回 BST 中的所有 众数&#xff08;即&#xff0c;出现频率最高的元素&#xff09;。 如果树中有不止一个众数&#xff0c;可以按 任意顺序 返回。 假定 BST 满…

PingCAP 王琦智:下一代 RAG,tidb.ai 使用知识图谱增强 RAG 能力

导读 随着 ChatGPT 的流行&#xff0c;LLMs&#xff08;大语言模型&#xff09;再次进入人们的视野。然而&#xff0c;在处理特定领域查询时&#xff0c;大模型生成的内容往往存在信息滞后和准确性不足的问题。如何让 RAG 和向量搜索技术在实际应用中更好地满足企业需求&#…

昇思25天学习打卡营第14天|计算机视觉

昇思25天学习打卡营第14天 文章目录 昇思25天学习打卡营第14天FCN图像语义分割语义分割模型简介网络特点数据处理数据预处理数据加载训练集可视化 网络构建网络流程 训练准备导入VGG-16部分预训练权重损失函数自定义评价指标 Metrics 模型训练模型评估模型推理总结引用 打卡记录…

Electron 和 React 开发桌面应用程序

目录 书籍推荐 Electron React 在线资源和教程 官方文档 在线教程 综合学习路径 经典开发案例 Visual Studio Code Hyper Tusk Notable Beekeeper Studio 开源项目和示例代码 Electron React Boilerplate Electron Forge + React Electron React Template 学…

FPGA开发在verilog中关于阻塞和非阻塞赋值的区别

一、概念 阻塞赋值&#xff1a;阻塞赋值的赋值号用“”表示&#xff0c;对应的是串行执行。 对应的电路结构往往与触发沿没有关系&#xff0c;只与输入电平的变化有关系。阻塞赋值的操作可以认为是只有一个步骤的操作&#xff0c;即计算赋值号右边的语句并更新赋值号左边的语句…

Transformer-Bert---散装知识点---mlm,nsp

本文记录的是笔者在了解了transformer结构后嗑bert中记录的一些散装知识点&#xff0c;有时间就会整理收录&#xff0c;希望最后能把transformer一个系列都完整的更新进去。 1.自监督学习 bert与原始的transformer不同&#xff0c;bert是使用大量无标签的数据进行预训…

规范:前后端接口规范

1、前言 随着互联网的高速发展&#xff0c;前端页面的展示、交互体验越来越灵活、炫丽&#xff0c;响应体验也要求越来越高&#xff0c;后端服务的高并发、高可用、高性能、高扩展等特性的要求也愈加苛刻&#xff0c;从而导致前后端研发各自专注于自己擅长的领域深耕细作。 然…

volatile,最轻量的同步机制

目录 一、volatile 二、如何使用&#xff1f; 三、volatile关键字能代替synchronized关键字吗&#xff1f; 四、总结&#xff1a; 还是老样子&#xff0c;先来看一段代码&#xff1a; 我们先由我们自己的常规思路分析一下代码&#xff1a;子线程中&#xff0c;一直循环&…