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 写在前面 最近在搞本科毕设,关于基于深度学 ...
随机推荐
- route - 显示 / 操作IP选路表
总览 SYNOPSIS route [-CFvnee] route [-v] [-A family] add [-net|-host] target [netmask Nm] [gw Gw] [met ...
- P与C
P是排列:与次序有关,P(5.3)=5*4*3 C是组合:与次序无关,C(5.3)=(5*4*3)/(3*2*1)
- 亲测可用的golang sql例程与包管理
sqlite与golang package main import ( "database/sql" "fmt" "time" _ &quo ...
- CF 36E Two Paths
传送门 真实的自闭= =+ 考试的时候老师明明说了可以路径为空T^T 然后光荣的挂掉了 20分的链[明明是最送分的] 上来就看出来欧拉回路了嘛 然后思考了一下大概奇点配个对 删一条简单路径剩下的跑欧拉 ...
- Sublime Text3添加C++编译与运行
安装MinGW 1.安装MinGW ,其安装方法一直下一步,安装完后点Continue会出现一个窗口,在Basic Setup下标记所有包,然后在菜单里点"Apply Changes&quo ...
- Spring Transaction Isolation
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11530702.html Reference http://docs.spring.io/spring/ ...
- Codeforces 499C:Crazy Town(计算几何)
题目链接 给出点A(x1,y1),B(x2,y2),和n条直线(ai,bi,ci,aix + biy + ci = 0),求A到B穿过多少条直线 枚举每条直线判断A.B是否在该直线两侧即可 #incl ...
- paper 160:python 知识点概要 更新ing
1.python json http://www.runoob.com/python/python-json.html Python的json模块提供了一种很简单的方式来编码和解码JSON数据. 其 ...
- HashMap的底层原理 cr:csdn:zhangshixi
1. HashMap概述: HashMap是基于哈希表的Map接口的非同步实现.此实现提供所有可选的映射操作,并允许使用null值和null键.此类不保证映射的顺序,特别是它不保证该顺序恒久不变 ...
- [CSP-S模拟测试]:平均数(二分答案+归并排序)
题目描述 有一天,小$A$得到了一个长度为$n$的序列.他把这个序列的所有连续子序列都列了出来,并对每一个子序列都求了其平均值,然后他把这些平均值写在纸上,并对它们进行排序,最后他报出了第$k$小的平 ...