DBOW概要理解与记录

news2024/9/21 0:37:40

前言

DBOW作为一种视觉回环技术被广泛应用在各类VSLAM框架中,之前的经验主要集中在使用和抽象理解层面,近期花了一些时间仔细阅读了相关论文和源码,这里做一些记录。

两个关键概念

Vocabulary

通过预先训练得到的词汇库,以树状数据结构保存,便于后续查询,如下图黄色部分:
在这里插入图片描述

  • 训练过程:通过数据集提取每张图片feature构成一个feature集,将feature集进行按层级的kmeans++聚类(每一层都进行一次聚类,得到centroid node作为节点),最终获取到d层共w个words,每一个word根据在数据集中的频次计算其weight并保存,待后续使用。
  • 查询过程:从根节点开始,将待查询feature(f)与每层的node计算hamming distance,选择最小值的node继续往下,依次从上到下贯穿整棵树,直到叶子节点,就得到其对应的word。

Dataset

上图中的蓝色部分,在实际使用中,需要实时构建数据库,用于后续查找回环。

  • 构建数据库:采集到的每张图片提取全部feature,所有feature通过vocabulary查询获取对应word,所有word构成这张图片对应的Bowvector,同时,根据word的weight与单张图片中该word出现比例可以计算得到value,这些信息将会构成一张反向索引表(所有包含某个word的图片索引)和一张正向索引表(每张图片保护的word索引及alue),这两张表实际上就是数据库,用于后面提取历史keyframe对应的图片的Bowvector。

回环检测过程

  • 1、构建自己的vocabulary并保存,这一步一般可以省略,可以直接使用作者提供的一份vocabulary file,如果效果不佳,可以考虑自己构建。
  • 2、运行自己的VIO算法,每一个keyframe对应的图片加入到dataset,实时构建dataset,代码如下:
inline DBow::EntryId DBow::Database::AddEntry(const vector<float>& features)
{
	DBow::BowVector v;
	m_voc->Transform(features, v, false);
	return _AddEntry(v);
}

EntryId Database::_AddEntry(BowVector &v)
{
	VocParams::ScoringType norm;
	if(VocParams::MustNormalize(m_voc->Scoring(), norm)){
		// vectors are stored normalized if needed
		v.Normalize(norm);
	}

	EntryId eid = m_nentries;

	// update inverted file
	BowVector::const_iterator it;
	for(it = v.begin(); it != v.end(); it++){
		// eids are in ascending order in the index
		m_index[it->id].push_back(IFEntry(eid, it->value));
	}

	m_nentries++;

	return eid;
}
  • 3、每一个新的keyframe对应的图片,加入dataset查询回环,具体过程是,将图片提取全部feature并通过vocabulary转换得到Bowvector,通过dataset查询相关的历史keyframe,计算当前keyframe与历史keyframe对应Bowvector的loss,计算算法有很多种类,如下:
	switch(info.Parameters->Scoring){
		
		case VocParams::L1_NORM:
			doQueryL1(v, ret, max_results, info.Parameters->ScaleScore);
			break;

		case VocParams::L2_NORM:
			doQueryL2(v, ret, max_results, info.Parameters->ScaleScore);
			break;

		case VocParams::CHI_SQUARE:
			doQueryChiSquare(v, ret, max_results, info.Parameters->ScaleScore);
			break;

		case VocParams::KL:
			doQueryKL(v, ret, max_results, info.Parameters->ScaleScore);
			break;

		case VocParams::BHATTACHARYYA:
			doQueryBhattacharyya(v, ret, max_results, info.Parameters->ScaleScore);
			break;

		case VocParams::DOT_PRODUCT:
			doQueryDotProduct(v, ret, max_results, info.Parameters->ScaleScore);
			break;
	}

得到score,对score进行排序获取candidates,如下:

void Database::doQueryL1(const BowVector &v, QueryResults &ret, 
						 const int max_results, const bool scale_score) const
{
	BowVector::const_iterator it;
	IFRow::const_iterator rit;
	QueryResults::iterator qit;
	
	for(it = v.begin(); it != v.end(); it++){
		WordId wid = it->id;
		WordValue qvalue = it->value;
		
		const IFRow& row = m_index[wid];

		for(rit = row.begin(); rit != row.end(); rit++){
			EntryId eid = rit->id;
			WordValue dvalue = rit->value;

			// scoring-dependent value
			double value = fabs(qvalue - dvalue) - fabs(qvalue) - fabs(dvalue);

			// check if this entry is already in the returning vector
			qit = find(ret.begin(), ret.end(), eid);

			if(qit == ret.end()){
				// insert
				ret.push_back(Result(eid, value));
			}else{
				// update
				qit->Score += value; 
			}
		} // for each inverted row 
	} // for each word in features	

	// resulting "scores" are now in [-2 best .. 0 worst]
	
	// sort vector in ascending order
	// (scores are inverted now --the lower the better--)
	sort(ret.begin(), ret.end());

	// cut vector
	if((int)ret.size() > max_results) ret.resize(max_results);

	// complete score
	// ||v - w||_{L1} = 2 + Sum(|v_i - w_i| - |v_i| - |w_i|) 
	//		for all i | v_i != 0 and w_i != 0 
	// (Nister, 2006)
	if(scale_score){
		for(qit = ret.begin(); qit != ret.end(); qit++) 
			qit->Score = -qit->Score/2.0;
	}else{
		for(qit = ret.begin(); qit != ret.end(); qit++) 
			qit->Score = 2.0 + qit->Score;
	}
}

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

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

相关文章

RISC-V架构——中断委托和中断注入

1、中断委托 1.1、中断委托的作用 &#xff08;1&#xff09;默认情况下&#xff0c;所有的陷入&#xff08;中断和异常&#xff09;都是在M模式下处理&#xff0c;然后再返回到发生陷入前的模式&#xff1b; &#xff08;2&#xff09;所有陷入都在M模式处理会涉及到模式切换…

Python 面向对象编程:类、对象、初始化和方法详解

Python 是一种面向对象的编程语言。在 Python 中&#xff0c;几乎所有东西都是对象&#xff0c;都具有其属性和方法。 类似于对象构造函数或用于创建对象的“蓝图”的类。 创建一个类 要创建一个类&#xff0c;请使用关键字 class&#xff1a; 示例&#xff0c;创建一个名为…

【数据结构】数组和字符串(三):特殊矩阵的压缩存储:三角矩阵、对称矩阵——一维数组

文章目录 4.2.1 矩阵的数组表示4.2.2 特殊矩阵的压缩存储a. 对角矩阵的压缩存储b. 三角矩阵的压缩存储结构体初始化元素设置元素获取打印矩阵主函数输出结果代码整合 c. 对称矩阵的压缩存储元素设置元素获取主函数输出结果代码整合 4.2.1 矩阵的数组表示 【数据结构】数组和字…

图像数据噪音种类以及Python生成对应噪音

前言 当涉及到图像处理和计算机视觉任务时&#xff0c;噪音是一个不可忽视的因素。噪音可以由多种因素引起&#xff0c;如传感器误差、通信干扰、环境光线变化等。这些噪音会导致图像质量下降&#xff0c;从而影响到后续的图像分析和处理过程。因此&#xff0c;对于从图像中获…

Thread同步问题,小案例

要求 有两个用户分别从同一个卡上取钱(总额&#xff1a;10000元)每次都取1000&#xff0c;当余额不足时&#xff0c;就不能取款了不能出现超取现象> 线程同步问题 public static void main(String[] args) {BankChoic bankChoic new BankChoic();Thread thread1 new Th…

设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1)

初始化及打印函数 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #define MaxSize 10//定义最大长度 int InitArr[10] { 1,2,3,4,5,6,7,8,9,10 };typedef struct {int data[MaxSize];//用静态的数据存放数据元素int length;//顺序表当前长度 }Sqlist;//顺序表的类…

苹果将于8月31日举行今秋的第二场发布会

在今日凌晨&#xff0c;苹果宣布&#xff0c;将于北京时间10月31日早上8点举行今秋的第二场发布会&#xff0c;主题为“来势迅猛”。据多方猜测苹果本次活动的核心产品大概率是搭载全新M3芯片的Mac系列产品。 据了解&#xff0c;在苹果的产品线中&#xff0c;搭载M3芯片的Mac系…

C++ BinarySercahTree recursion version

for循环版本的&#xff1a;C BinarySercahTree for version-CSDN博客 Inorder()在c BinarySerschTree for verison写了。 还是按照那种嵌套的方式来写递归。 现在来写查找 FindR() bool FindR(){return _FindR(_root);}然后_FindR()函数写递归具体实现&#xff1a; 假设要…

HAL库 CubeMX STM32采用SDIO实现对SD卡和NAND Flash的读写

目录 一、选择合适的存储芯片。 可以去雷龙官网白嫖&#xff0c;白嫖链接&#xff1a;免费样品 二、SD卡/SD NAND底层原理 三、 CubeMX配置STM32具体步骤 1、时钟和系统配置 2、配置SDIO 3、配置DMA &#xff08;可选&#xff09; 4、设置串口 四、代码编写 1、公共…

vue 数据劫持代理原理

function lianxi(){// vue 数据劫持代理let data {username:curry,age:33}//模拟组件的实例let _this {}//利用Object.defineProperty()for( let item in data){//console.log(item,data[item])Object.defineProperty(_this,item,{//get:用来获取扩展属性值的,当获取该属性值…

基本指令(2):通配符,重定向,命令行管道

一、通配符 rm -rf ./* # * —— 通配符&#xff0c;指定路径下的所有文件&#xff08;不包括隐藏文件&#xff09;二、重定向 在理解重定向前&#xff0c;先要有一个概念&#xff1a;Linux下一切皆文件&#xff0c;大部分硬件设备都可以看做有读写方法&#xff0c;只不过有些方…

Web前端免费接入Microsoft Azure AI文本翻译,享每月2百万个字符的翻译

Azure 文本翻译是 Azure AI 翻译服务的一项基于云的 REST API 功能。 文本翻译 API 支持实时快速准确地进行源到目标文本翻译。 文本翻译软件开发工具包 (SDK) 是一组库和工具&#xff0c;可用于轻松地将文本翻译 REST API 功能集成到应用程序中。 文本翻译 SDK 可跨 C#/.NET、…

国腾GM8775C完全替代CS5518 MIPIDSI转2 PORT LVDS

集睿致远CS5518描述&#xff1a; CS5518是一款MIPI DSI输入、LVDS输出转换芯片。MIPI DSI 支持多达4个局域网&#xff0c;每条通道以最 大 1Gbps 的速度运行。LVDS支持18位或24位像素&#xff0c;25Mhz至154Mhz&#xff0c;采用VESA或JEIDA格 式。它只能使用单个1.8v电源&am…

人脸活体检测:Domain-Generalized Face Anti-Spoofing with Unknown Attacks

论文作者&#xff1a;Zong-Wei Hong,Yu-Chen Lin,Hsuan-Tung Liu,Yi-Ren Yeh,Chu-Song Chen 作者单位&#xff1a;National Taiwan University; E.SUN Financial Holding Co., Ltd.; National Kaohsiung Normal University 论文链接&#xff1a;http://arxiv.org/abs/2310.11…

Echarts多曲线数值与Y周刻度不符合

发现问题&#xff1a; 在展示多曲线图表的时候&#xff0c;发现图表曲线数值相差不大&#xff0c;但是图表展示的曲线相差很大&#xff0c;仔细观察之后发现是展示有问题(其实这并不能算是错误&#xff0c;只是由于忽略&#xff0c;导致的配置与预期不符合)。 问题复现&#x…

【低代码平台】JeecgBoot代码生成器如何使用?Online代码生成

Online代码生成 目前Vue3已经支持两种模式&#xff1a;Online在线模式 和 GUI模式代码生成。 JeecgBoot版本要求&#xff1a; 3.2.0 ( 提供了vue3、vue3Native模板目录 ) 第一步&#xff1a;通过online表单在线建表 jeecg提供了在线建表的功能&#xff0c;找到菜单&#xff1a;…

关于城市综合管廊分析与应用

安科瑞 华楠 摘要&#xff1a;文章介绍了城市综合管廊的概念和我国综合管廊建设的背景&#xff0c;并总结归纳了综合管廊的设计要点以及注意事项&#xff0c;为今后的综合管廊设计提供参考。 关键词&#xff1a;城市&#xff1b;综合管廊&#xff1b;应用 1 规划背景及技术路…

GEE案例——一个完整的火灾监测案例dNBR差异化归一化烧毁指数

差异化归一化烧毁指数 dNBR是"差异化归一化烧毁指数"的缩写。它是一种用于评估卫星图像中烧毁区域严重程度的遥感指数。dNBR值通过将火灾前的归一化烧毁指数(NBR)减去火灾后的NBR来计算得出。该指数常用于野火监测和评估。 dNBR(差异化归一化烧毁指数)是一种用…

报错:Could not resolve host: mirrorlist.centos.org;Unknown error

报错&#xff1a;Could not resolve host: mirrorlist.centos.org;Unknown error 一般是因为网络配置错误导致无法连接外网&#xff0c;我们先尝试ping一下www.baidu.com发现无法ping通。 果然&#xff0c;接下来我们就开始排查吧&#xff01;&#xff01; 1.网络配置查看 打开…

LeetCode88——合并两个有序数组

LeetCode88——合并两个有序数组 1.题目描述&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递减…