VINS 检测回环辅助激光建图
最近接到一个任务,在激光检测回环失败时,比如黑色物体多,场景大等,可否利用视觉进行回环检测。如果只是检测回环,现有的许多框架都可以使用。ORB-SLAM本身就有单目模式,且效果不错。但是发现ORB在检测回环时,必须要进行pose计算,产生地图点,然后根据地图点和回环之间的关系进行回环检测。这样就比较耗费资源,可否只检测回环,并不计算位姿与地图点。然后想到VINS也是有单目检测回环功能,就着手从VINS开始。
1. feature_tracker模块
这部分模块无需较大改动,只需要在节点里增加激光数据触发信号,让激光关键帧与图象帧保持数据同步
2. estimator模块
此部分会融合IMU做pose计算,所以这个节点在回环检测中不需要使用。需要在launch文件中,删去此节点,不运行。
3. pose_graph模块
3.1 此部分为回环检测核心模块
首先修改订阅的topic,只需要订阅图像与feature_tracker发布的特征点信息。
ros::Subscriber sub_image = n.subscribe(IMAGE_TOPIC, 2000, image_callback);
ros::Subscriber sub_point = n.subscribe("/feature_tracker/feature", 2000, point_callback);
3.2 修改KeyFrame构造函数
以前的需要特征点对应的3D点,此时为了减少计算量,只需要特征点图像坐标与归一化坐标,以及特征点光流平均速度
KeyFrame::KeyFrame(double _time_stamp, int _index, cv::Mat &_image,vector<cv::Point2f> &_point_2d_uv, vector<cv::Point2f> &_point_2d_normal, double _aver_velocity, int _sequence)
{
time_stamp = _time_stamp;
index = _index;
image = _image.clone();
cv::resize(image, thumbnail, cv::Size(80, 60));
std::cout<<"this is resize"<<std::endl;
point_2d_uv = _point_2d_uv;
point_2d_norm = _point_2d_normal;
has_loop = false;
loop_index = -1;
has_fast_point = false;
loop_info << 0, 0, 0, 0, 0, 0, 0, 0;
sequence = _sequence;
computeWindowBRIEFPoint();
computeBRIEFPoint();
aver_velocity = _aver_velocity;
//这里可以把图像清除了,但是为了显示图像,可以暂且留着
}
3.3 改动的还有addkeyFrame
为了减少计算量,当机器人静止时,可以不需要进行回环检测,这里判断条件就是特征点的平均光溜速度,对于这个阈值可以根据最小视差来决定。
void PoseGraph::addKeyFrame(KeyFrame* cur_kf, bool flag_detect_loop)
{
//先判断是否关键帧
std::cout<<"this is function of addKeyFrame"<<std::endl;
if(cur_kf->aver_velocity<=0.2&&keyframelist.size()>0)
{
std::cout<<"loop index unchanged"<<last_loop_index<<std::endl;
}else{
if (sequence_cnt != cur_kf->sequence)
{
sequence_cnt++;
sequence_loop.push_back(0);
}
cur_kf->index = global_index;
last_index= global_index;
int loop_index = -1;
if (flag_detect_loop)
{
TicToc tmp_t;
loop_index = detectLoop(cur_kf, cur_kf->index);
last_loop_index = loop_index;
std::cout<<"loop index is "<<loop_index<<std::endl;
KeyFrame * old_kf = getKeyFrame(loop_index);
if(loop_index !=-1)
{
if(cur_kf->findConnection(old_kf))
{
std::cout<<"this is true loop with index of : "<< loop_index<<std::endl;
}
}
}
global_index++;
keyframelist.push_back(cur_kf);
}
}
detectLoop函数没有做改动,对与findConnection函数做了如下改动。一开始以为可以不需要findConnection函数,直接用detectLoop得出的结果就能使用了,但是发现误匹配很多,VINS之前是使用
PnPRANSAC(matched_2d_old_norm, matched_3d, status, PnP_T_old, PnP_R_old);
函数进行两帧之间的真实相似度检测。但是此函数需要3D点,且计算了相对位姿,并不适合我的任务,正好VINS的老版本仅仅使用了两帧图像的2d点进行验证,虽然精度略微降低,但是无需3D点,减少了计算量。
bool KeyFrame::findConnection(KeyFrame* old_kf)
{
std::cout<<"this is function of findConnection"<<std::endl;
TicToc tmp_t;
//printf("find Connection\n");
vector<cv::Point2f> matched_2d_cur, matched_2d_old;
vector<cv::Point2f> matched_2d_cur_norm, matched_2d_old_norm;
vector<uchar> status;
matched_2d_cur = point_2d_uv;
matched_2d_cur_norm = point_2d_norm;
TicToc t_match;
std::cout<<"old_kf keypoint : "<<old_kf->keypoints.size()<<std::endl;
searchByBRIEFDes(matched_2d_old, matched_2d_old_norm, status, old_kf->brief_descriptors, old_kf->keypoints, old_kf->keypoints_norm);
reduceVector(matched_2d_cur, status);
reduceVector(matched_2d_old, status);
reduceVector(matched_2d_cur_norm, status);
reduceVector(matched_2d_old_norm, status);
//printf("search by des finish\n");
status.clear();
if ((int)matched_2d_cur.size() > MIN_LOOP_NUM)
{
status.clear();
FundmantalMatrixRANSAC(matched_2d_cur_norm,matched_2d_old_norm,status);
reduceVector(matched_2d_cur, status);
reduceVector(matched_2d_old, status);
reduceVector(matched_2d_cur_norm, status);
reduceVector(matched_2d_old_norm, status);
int gap = 10;
cv::Mat gap_image(ROW, gap, CV_8UC1, cv::Scalar(255, 255, 255));
cv::Mat gray_img, loop_match_img;
cv::Mat old_img = old_kf->image;
cv::hconcat(image, gap_image, gap_image);
cv::hconcat(gap_image, old_img, gray_img);
cvtColor(gray_img, loop_match_img, CV_GRAY2RGB);
for(int i = 0; i< (int)matched_2d_cur.size(); i++)
{
cv::Point2f cur_pt = matched_2d_cur[i];
cv::circle(loop_match_img, cur_pt, 5, cv::Scalar(0, 255, 0));
}
for(int i = 0; i< (int)matched_2d_old.size(); i++)
{
cv::Point2f old_pt = matched_2d_old[i];
old_pt.x += (COL + gap);
cv::circle(loop_match_img, old_pt, 5, cv::Scalar(0, 255, 0));
}
for (int i = 0; i< (int)matched_2d_cur.size(); i++)
{
cv::Point2f old_pt = matched_2d_old[i];
old_pt.x += (COL + gap) ;
cv::line(loop_match_img, matched_2d_cur[i], old_pt, cv::Scalar(0, 255, 0), 2, 8, 0);
}
cv::Mat notation(50, COL + gap + COL, CV_8UC3, cv::Scalar(255, 255, 255));
putText(notation, "current frame: " + to_string(index) + " sequence: " + to_string(sequence), cv::Point2f(20, 30), CV_FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 3);
putText(notation, "previous frame: " + to_string(old_kf->index) + " sequence: " + to_string(old_kf->sequence), cv::Point2f(20 + COL + gap, 30), CV_FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255), 3);
cv::vconcat(notation, loop_match_img, loop_match_img);
if ((int)matched_2d_cur.size() > MIN_LOOP_NUM)
{
cv::imshow("loop connection",loop_match_img);
cv::waitKey(100);
return true;
}
}
//printf("loop final use num %d %lf--------------- \n", (int)matched_2d_cur.size(), t_match.toc());
return false;
}
效果如图所示。
VINS 检测回环辅助激光建图的更多相关文章
- 综述 | SLAM回环检测方法
本文作者任旭倩,公众号:计算机视觉life成员,由于格式原因,公式显示可能出问题,建议阅读原文链接:综述 | SLAM回环检测方法 在视觉SLAM问题中,位姿的估计往往是一个递推的过程,即由上一帧位姿 ...
- cartographer环境建立以及建图测试(详细级)
- 第五篇 openvslam建图与优化模块梳理
建图模块 mapping_module在初始化系统的时候进行实例化,在构建实例的时候会实例化local_map_cleaner和local_bundle_adjuster.系统启动的时候会在另外一个线 ...
- java下蛇形回环矩阵的实现
前文废话:这个问题据说是腾讯之前的一道笔试题,由于当时没认真看,现在记不清这种矩阵是不是叫"蛇形回环矩阵"......请大家直接看图1,就是那个样子的矩阵. 问题描述:输入一个N, ...
- VINS 回环检测与全局优化
回环检测 VINS回环检测与全局优化都在pose_graph.cpp内处理.首先在pose_graph_node加载vocabulary文件给BriefDatabase用,如果要加载地图,会loadP ...
- segMatch:基于3D点云分割的回环检测
该论文的地址是:https://arxiv.org/pdf/1609.07720.pdf segmatch是一个提供车辆的回环检测的技术,使用提取和匹配分割的三维激光点云技术.分割的例子可以在下面的图 ...
- ORB-SLAM(六)回环检测
上一篇提到,无论在单目.双目还是RGBD中,追踪得到的位姿都是有误差的.随着路径的不断延伸,前面帧的误差会一直传递到后面去,导致最后一帧的位姿在世界坐标系里的误差有可能非常大.除了利用优化方法在局部和 ...
- Code Reading: ORB-SLAM回环检测源码阅读+注释
之前研究过一些回环检测的内容,首先要看的自然是用词袋回环的鼻祖和正当继承人(没有冒犯VINS和LDSO的意思)ORB-SLAM.下面是我的代码注释.因为代码都是自己手打的,不是在源码上注释的,所以一些 ...
- 一个基于深度学习回环检测模块的简单双目 SLAM 系统
转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12634631.html 写在前面 最近在搞本科毕设,关于基于深度学 ...
随机推荐
- Springmvc上传过程中遇到的错误
问题1: org.springframework.web.util.NestedServletException: Handler processing failed; nested exceptio ...
- windows和mtu值修改
前言 有时候我们需要修改mtu值来对付乱七八糟的网络问题 windows修改方法 1.netsh interface ipv4 show subinterfaces 查询到目前系统的MTU值 2.ne ...
- No enclosing instance of type TestGson is accessible. Must qualify the allocation with an enclosing instance of type TestGson (e.g. x.new A() where x is an instance of TestGson).
main方法中实例化内部类报错: public class TestGson { public static void main(String[] args) { Gson gson=new Gson ...
- 第01章 Spring概述
第01章 Spring概述 1.Spring概述 ①Spring是一个开源框架 ②Spring为简化企业级开发而生,使用Spring,JavaBean就可以实现很多以前要靠EJB才能实现的功能.同样的 ...
- ARC062F AtCoDeerくんとグラフ色塗り / Painting Graphs with AtCoDeer Burnside 引理
题目传送门 https://atcoder.jp/contests/arc062/tasks/arc062_d 题解 首先对整张图做 Tarjan 点双. 对于一个点双,如果是由一条边构成的,那么很显 ...
- python代码整体左移或右移
IDE 是 PyCharm 选中代码块: 1)右移:直接 Tab 2)左移:Shift + Tab
- find命令进阶用法(一)
-cmin n: 查找 exactly n 分钟前内容或属性被最后修过的文件 -cnewer file: 查找内容或属性的最后修改时间晚于file文件的文件 -ctime n: 查找 **n*24** ...
- 每天一个linux命令:head(15)
head head命令用于显示文件的开头的内容.在默认情况下,head命令显示文件的头10行内容. 格式 head [参数] [文件] 参数选项 参数 备注 -q 不显示文件名的头信息 -v 总是 ...
- Redis缓存在django中的配置
django settings中的配置 # 缓存 CACHES = { "default": { "BACKEND": "django_redis. ...
- c# 如何获取系统管理员权限(UAC) 及判断当前是否是管理员权限
环境说明: VS2012,windows 7 亲自验证过win7 和xp ,XP直接不弹框,因为XP没有UAC控制机制 步骤1: 右键项目-->属性-->安全性-->选中[启用Cl ...