当前位置: 首页 > 编程日记 > 正文

ORB_SLAM2局部建图线程

局部建图线程入口:可执行程序在初始化三个线程的时候,在System.cc的构造函数中进入局部建图线程

    mpLocalMapper = new LocalMapping(mpMap, 				//指定使iomanipmSensor==MONOCULAR);	// TODO 为什么这个要设置成为MONOCULAR???//运行这个局部建图线程mptLocalMapping = new thread(&ORB_SLAM2::LocalMapping::Run,	//这个线程会调用的函数mpLocalMapper);				//这个调用函数的参数

插入关键帧

将关键帧插入到关键帧列表中

void LocalMapping::InsertKeyFrame(KeyFrame *pKF)
// 插入关键帧,由外部(Tracking)线程调用;这里只是插入到列表中,等待线程主函数对其进行处理
void LocalMapping::InsertKeyFrame(KeyFrame *pKF)
{unique_lock<mutex> lock(mMutexNewKFs);// 将关键帧插入到列表中mlNewKeyFrames.push_back(pKF);mbAbortBA=true;
}


处理关键帧

void LocalMapping::ProcessNewKeyFrame()

Tracking线程将关键帧插入了队列中,该函数取出一个关键帧进行处理:建立路标点与关键帧的联系,更新共视图,将关键帧插入地图中。
在这里插入图片描述

    {unique_lock<mutex> lock(mMutexNewKFs);// 取出列表中最前面的关键帧,作为当前要处理的关键帧mpCurrentKeyFrame = mlNewKeyFrames.front();// 取出最前面的关键帧后,在原来的列表里删掉该关键帧mlNewKeyFrames.pop_front();}

计算关键帧的词袋信息

会更新关键帧数据库(存储所有关键帧的词典)。
在这里插入图片描述

mpCurrentKeyFrame->ComputeBoW();

建立当前帧与路标点的联系

在追踪局部地图时,只是建立了特征点和路标点间的匹配关系,并没有建立联系。
在这里插入图片描述

    const vector<MapPoint*> vpMapPointMatches = mpCurrentKeyFrame->GetMapPointMatches();// 对当前处理的这个关键帧中的所有的地图点展开遍历for(size_t i=0; i<vpMapPointMatches.size(); i++){MapPoint* pMP = vpMapPointMatches[i];if(pMP){if(!pMP->isBad()){if(!pMP->IsInKeyFrame(mpCurrentKeyFrame)){// 如果地图点不是来自当前帧的观测,为当前地图点添加观测pMP->AddObservation(mpCurrentKeyFrame, i);// 获得该点的平均观测方向和观测距离范围pMP->UpdateNormalAndDepth();// 更新地图点的最佳描述子pMP->ComputeDistinctiveDescriptors();}else // this can only happen for new stereo points inserted by the Tracking{// 如果当前帧中已经包含了这个地图点,但是这个地图点中却没有包含这个关键帧的信息// 这些地图点可能来自双目或RGBD跟踪过程中新生成的地图点,或者是CreateNewMapPoints 中通过三角化产生// 将上述地图点放入mlpRecentAddedMapPoints,等待后续MapPointCulling函数的检验mlpRecentAddedMapPoints.push_back(pMP); }}}} 

更新关键帧间的联系(共视图)

在这里插入图片描述

mpCurrentKeyFrame->UpdateConnections();

关键帧插入地图

mpMap->AddKeyFrame(mpCurrentKeyFrame);


剔除错误路标点

mlpRecentAddedMapPoints:当前关键帧中待检测的地图点集合。

void LocalMapping::MapPointCulling()

剔除条件1

** 地图点被追踪的次数/预计被看到的次数<0.25**
** 地图点被追踪的次数指的是:地图点投影到关键帧中,和多少关键帧的特征点形成了匹配。
预计被看到的次数指的是:该地图点在多少帧的视野范围内。**

        else if(pMP->GetFoundRatio()<0.25f){// Step 2.2:跟踪到该MapPoint的Frame数相比预计可观测到该MapPoint的Frame数的比例小于25%,删除// (mnFound/mnVisible) < 25%// mnFound :地图点被多少帧(包括普通帧)看到,次数越多越好// mnVisible:地图点应该被看到的次数// (mnFound/mnVisible):对于大FOV镜头这个比例会高,对于窄FOV镜头这个比例会低pMP->SetBadFlag();lit = mlpRecentAddedMapPoints.erase(lit);}

剔除条件2

该路标点可以被3个以上的关键帧观测到,否则剔除

        else if(((int)nCurrentKFid-(int)pMP->mnFirstKFid)>=2 && pMP->Observations()<=cnThObs){// Step 2.3:从该点建立开始,到现在已经过了不小于2个关键帧// 但是观测到该点的关键帧数却不超过cnThObs帧,那么删除该点pMP->SetBadFlag();lit = mlpRecentAddedMapPoints.erase(lit);}else if(((int)nCurrentKFid-(int)pMP->mnFirstKFid)>=3)// Step 2.4:从建立该点开始,已经过了3个关键帧而没有被剔除,则认为是质量高的点// 因此没有SetBadFlag(),仅从队列中删除,放弃继续对该MapPoint的检测lit = mlpRecentAddedMapPoints.erase(lit);elselit++;


检查关键帧列表是否为空

bool LocalMapping::CheckNewKeyFrames()
{unique_lock<mutex> lock(mMutexNewKFs);return(!mlNewKeyFrames.empty());
}

创建新地图点

获得数据

(1)取出与当前帧共视程度最高的几个关键帧。

 const vector<KeyFrame*> vpNeighKFs = mpCurrentKeyFrame->GetBestCovisibilityKeyFrames(nn);

(2)获取当前关键帧的变换矩阵:由旋转矩阵和平移矩阵组成

    cv::Mat Rcw1 = mpCurrentKeyFrame->GetRotation();cv::Mat Rwc1 = Rcw1.t();cv::Mat tcw1 = mpCurrentKeyFrame->GetTranslation();cv::Mat Tcw1(3,4,CV_32F);Rcw1.copyTo(Tcw1.colRange(0,3));tcw1.copyTo(Tcw1.col(3));

(3)获得相机光心坐标、内参

    cv::Mat Ow1 = mpCurrentKeyFrame->GetCameraCenter();const float &fx1 = mpCurrentKeyFrame->fx;const float &fy1 = mpCurrentKeyFrame->fy;const float &cx1 = mpCurrentKeyFrame->cx;const float &cy1 = mpCurrentKeyFrame->cy;const float &invfx1 = mpCurrentKeyFrame->invfx;const float &invfy1 = mpCurrentKeyFrame->invfy;

遍历共视程度最高的关键帧

(1)判断是否需要对每个相邻的关键进行三角化,需要满足一定的稀疏性。单目应满足的条件:
两帧间基线的长度要大于路标点平均深度的一个比例。

        else    {// 单目相机情况// 邻接关键帧的场景深度中值const float medianDepthKF2 = pKF2->ComputeSceneMedianDepth(2);// baseline与景深的比例const float ratioBaselineDepth = baseline/medianDepthKF2;// 如果比例特别小,基线太短恢复3D点不准,那么跳过当前邻接的关键帧,不生成3D点if(ratioBaselineDepth<0.01)continue;}

(2)根据两个关键帧的位姿计算它们之间的基础矩阵

cv::Mat F12 = ComputeF12(mpCurrentKeyFrame,pKF2);

(3)通过BoW对两关键帧的未匹配的特征点快速匹配,并使用极线约束

        vector<pair<size_t,size_t> > vMatchedIndices;matcher.SearchForTriangulation(mpCurrentKeyFrame,pKF2,F12,vMatchedIndices,false);

对每对匹配通过三角化生成3D点

(1)获得视差角

            // 归一化坐标cv::Mat xn1 = (cv::Mat_<float>(3,1) << (kp1.pt.x-cx1)*invfx1, (kp1.pt.y-cy1)*invfy1, 1.0);cv::Mat xn2 = (cv::Mat_<float>(3,1) << (kp2.pt.x-cx2)*invfx2, (kp2.pt.y-cy2)*invfy2, 1.0);// 由相机坐标系转到世界坐标系// 是一个相机光心---->路标点的方向向量cv::Mat ray1 = Rwc1*xn1;cv::Mat ray2 = Rwc2*xn2;// 这个就是求向量之间角度公式const float cosParallaxRays = ray1.dot(ray2)/(cv::norm(ray1)*cv::norm(ray2));

(2)如果视差角满足约束,则使用SVD分解进行三角化,求出路标点的世界坐标

            if(cosParallaxRays<cosParallaxStereo && cosParallaxRays>0 && (bStereo1 || bStereo2 || cosParallaxRays<0.9998)){// Linear Triangulation Method// 见Initializer.cc的 Triangulate 函数,实现是一样的,顶多就是把投影矩阵换成了变换矩阵cv::Mat A(4,4,CV_32F);A.row(0) = xn1.at<float>(0)*Tcw1.row(2)-Tcw1.row(0);A.row(1) = xn1.at<float>(1)*Tcw1.row(2)-Tcw1.row(1);A.row(2) = xn2.at<float>(0)*Tcw2.row(2)-Tcw2.row(0);A.row(3) = xn2.at<float>(1)*Tcw2.row(2)-Tcw2.row(1);cv::Mat w,u,vt;cv::SVD::compute(A,w,u,vt,cv::SVD::MODIFY_A| cv::SVD::FULL_UV);x3D = vt.row(3).t();// 归一化之前的检查if(x3D.at<float>(3)==0)continue;// 归一化成为齐次坐标,然后提取前面三个维度作为欧式坐标x3D = x3D.rowRange(0,3)/x3D.at<float>(3);}

(3)判断三角化后的路标点是否满足约束
1)深度大于0
2)重投影误差小于阈值

            // Step 6.5:检测生成的3D点是否在相机前方,不在的话就放弃这个点float z1 = Rcw1.row(2).dot(x3Dt)+tcw1.at<float>(2);if(z1<=0)continue;float z2 = Rcw2.row(2).dot(x3Dt)+tcw2.at<float>(2);if(z2<=0)continue;//Check reprojection error in first keyframe// Step 6.6:计算3D点在当前关键帧下的重投影误差const float &sigmaSquare1 = mpCurrentKeyFrame->mvLevelSigma2[kp1.octave];const float x1 = Rcw1.row(0).dot(x3Dt)+tcw1.at<float>(0);const float y1 = Rcw1.row(1).dot(x3Dt)+tcw1.at<float>(1);const float invz1 = 1.0/z1;if(!bStereo1){// 单目情况下float u1 = fx1*x1*invz1+cx1;float v1 = fy1*y1*invz1+cy1;float errX1 = u1 - kp1.pt.x;float errY1 = v1 - kp1.pt.y;// 假设测量有一个像素的偏差,2自由度卡方检验阈值是5.991if((errX1*errX1+errY1*errY1)>5.991*sigmaSquare1)continue;}

建立新的地图点与帧、地图间的联系

地图点放入队列中,等待检测

融合相邻帧中的路标点

因为在局部建图线程中,创建了很多新的路标点,因此需要进行融合。

获得一阶、二阶共视关键帧

    // 开始之前先定义几个概念// 当前关键帧的邻接关键帧,称为一级相邻关键帧,也就是邻居// 与一级相邻关键帧相邻的关键帧,称为二级相邻关键帧,也就是邻居的邻居// 单目情况要10个邻接关键帧,双目或者RGBD则要20个int nn = 10;if(mbMonocular)nn=20;// 和当前关键帧相邻的关键帧,也就是一级相邻关键帧const vector<KeyFrame*> vpNeighKFs = mpCurrentKeyFrame->GetBestCovisibilityKeyFrames(nn);// Step 2:存储一级相邻关键帧及其二级相邻关键帧vector<KeyFrame*> vpTargetKFs;// 开始对所有候选的一级关键帧展开遍历:for(vector<KeyFrame*>::const_iterator vit=vpNeighKFs.begin(), vend=vpNeighKFs.end(); vit!=vend; vit++){KeyFrame* pKFi = *vit;// 没有和当前帧进行过融合的操作if(pKFi->isBad() || pKFi->mnFuseTargetForKF == mpCurrentKeyFrame->mnId)continue;// 加入一级相邻关键帧    vpTargetKFs.push_back(pKFi);// 标记已经加入pKFi->mnFuseTargetForKF = mpCurrentKeyFrame->mnId;// Extend to some second neighbors// 以一级相邻关键帧的共视关系最好的5个相邻关键帧 作为二级相邻关键帧const vector<KeyFrame*> vpSecondNeighKFs = pKFi->GetBestCovisibilityKeyFrames(5);// 遍历得到的二级相邻关键帧for(vector<KeyFrame*>::const_iterator vit2=vpSecondNeighKFs.begin(), vend2=vpSecondNeighKFs.end(); vit2!=vend2; vit2++){KeyFrame* pKFi2 = *vit2;// 当然这个二级相邻关键帧要求没有和当前关键帧发生融合,并且这个二级相邻关键帧也不是当前关键帧if(pKFi2->isBad() || pKFi2->mnFuseTargetForKF==mpCurrentKeyFrame->mnId || pKFi2->mnId==mpCurrentKeyFrame->mnId)continue;// 存入二级相邻关键帧    vpTargetKFs.push_back(pKFi2);}}

进行路标点融合

	// Step 3:将当前帧的地图点分别与一级二级相邻关键帧地图点进行融合 -- 正向vector<MapPoint*> vpMapPointMatches = mpCurrentKeyFrame->GetMapPointMatches();for(vector<KeyFrame*>::iterator vit=vpTargetKFs.begin(), vend=vpTargetKFs.end(); vit!=vend; vit++){KeyFrame* pKFi = *vit;// 将地图点投影到关键帧中进行匹配和融合;融合策略如下// 1.如果地图点能匹配关键帧的特征点,并且该点有对应的地图点,那么选择观测数目多的替换两个地图点// 2.如果地图点能匹配关键帧的特征点,并且该点没有对应的地图点,那么为该点添加该投影地图点// 注意这个时候对地图点融合的操作是立即生效的matcher.Fuse(pKFi,vpMapPointMatches);}// Search matches by projection from target KFs in current KF// Step 4:将一级二级相邻关键帧地图点分别与当前关键帧地图点进行融合 -- 反向// 用于进行存储要融合的一级邻接和二级邻接关键帧所有MapPoints的集合vector<MapPoint*> vpFuseCandidates;vpFuseCandidates.reserve(vpTargetKFs.size()*vpMapPointMatches.size());//  Step 4.1:遍历每一个一级邻接和二级邻接关键帧,收集他们的地图点存储到 vpFuseCandidatesfor(vector<KeyFrame*>::iterator vitKF=vpTargetKFs.begin(), vendKF=vpTargetKFs.end(); vitKF!=vendKF; vitKF++){KeyFrame* pKFi = *vitKF;vector<MapPoint*> vpMapPointsKFi = pKFi->GetMapPointMatches();// 遍历当前一级邻接和二级邻接关键帧中所有的MapPoints,找出需要进行融合的并且加入到集合中for(vector<MapPoint*>::iterator vitMP=vpMapPointsKFi.begin(), vendMP=vpMapPointsKFi.end(); vitMP!=vendMP; vitMP++){MapPoint* pMP = *vitMP;if(!pMP)continue;// 如果地图点是坏点,或者已经加进集合vpFuseCandidates,跳过if(pMP->isBad() || pMP->mnFuseCandidateForKF == mpCurrentKeyFrame->mnId)continue;// 加入集合,并标记已经加入pMP->mnFuseCandidateForKF = mpCurrentKeyFrame->mnId;vpFuseCandidates.push_back(pMP);}}// Step 4.2:进行地图点投影融合,和正向融合操作是完全相同的// 不同的是正向操作是"每个关键帧和当前关键帧的地图点进行融合",而这里的是"当前关键帧和所有邻接关键帧的地图点进行融合"matcher.Fuse(mpCurrentKeyFrame,vpFuseCandidates);

更新当前帧路标点的特性

    vpMapPointMatches = mpCurrentKeyFrame->GetMapPointMatches();for(size_t i=0, iend=vpMapPointMatches.size(); i<iend; i++){MapPoint* pMP=vpMapPointMatches[i];if(pMP){if(!pMP->isBad()){// 在所有找到pMP的关键帧中,获得最佳的描述子pMP->ComputeDistinctiveDescriptors();// 更新平均观测方向和观测距离pMP->UpdateNormalAndDepth();}}}

更新共视图

mpCurrentKeyFrame->UpdateConnections();


局部地图BA优化

Optimizer::LocalBundleAdjustment(mpCurrentKeyFrame,&mbAbortBA, mpMap);

对局部地图进行全局优化。
  优化变量:当前关键帧以及与当前关键帧具有一定共视关系的关键帧的位姿、路标点坐标。
  那些能观测到路标点,但无法达到公式关系阈值的关键帧,会提供约束,但不会进行优化。


检测冗余的关键帧

检测当前关键帧在共视图中的关键帧,根据地图点在共视图中的冗余程度剔除该共视关键帧。
  冗余关键帧的判定:90%以上的地图点能被其他关键帧(至少3个)观测到。

void LocalMapping::KeyFrameCulling()

获得公式关键帧

vector<KeyFrame*> vpLocalKeyFrames = mpCurrentKeyFrame->GetVectorCovisibleKeyFrames();

遍历共视关键帧

(1)遍历某一共视关键帧的所有地图点
(2)如果该共视关键帧中的路标点的90%以上被3个关键帧观测到,则该公式关键帧视为冗余关键帧,删除该关键帧


总结

l 局部建图线程在可执行程序初始化时进入,直接调用LocalMapping::Run函数。
流程为:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

(1)先将标志位置为FALSE,使得Tracking线程产生关键帧时,不再送入局部建图线程中。

SetAcceptKeyFrames(false);

(2)在队列mlNewKeyFrames中取出一个关键帧,进行处理

ProcessNewKeyFrame();

1)计算关键帧的词袋,更新关键帧数据库。
2)在追踪局部地图时,匹配了局部地图中的路标点和关键帧的特征点,但未建立联系。因此建立关键帧的路标点与该关键帧的联系。同时将路标点加入到待检测变量中()
3)更新共视图(只是更新当前帧及其有共视关系的关键帧间的权重)。
4)将关键帧插入到地图中。

(3)去除错误路标点

MapPointCulling();

遍历待检测的地图点,去除错误地图点的条件为:
1) 地图点被追踪的次数/预计被看到的次数<0.25
2)该路标点可以被3个以上的关键帧观测到,否则剔除
(4)创建新的地图点

CreateNewMapPoints();

如果不创建新的地图点的话,已知深度的地图点会越来越少,以至于后面无法继续追踪。
1)找到与当前帧共视程度最高的n个关键帧
2)遍历所有候选关键帧,使用词袋加速算法+极线约束寻找匹配的特征点
3)对每对特征点进行三角化测距
4)建立路标点与关键帧、局部地图的联系
(5)重复特征点的融合
创建了新的路标点之后,与这个路标点1匹配的特征点之前可能有匹配的路标点2。这是需要在路标点1、路标点2中进行选择。

SearchInNeighbors();

1)寻找当前关键帧的候选关键帧(共视点多)
2)将当前帧的路标点与每个候选关键帧的特征点进行重新匹配。
2)将所有候选关键帧的路标点与当前帧的特征点进行重新匹配。
(6)全局BA优化

Optimizer::LocalBundleAdjustment(mpCurrentKeyFrame,&mbAbortBA, mpMap);

优化的是当前关键帧及其共视关键帧的位姿与路标点的坐标。这里的共视关键帧指的是共视路标点的数目超过一个阈值。对于那些共视路标点没有超过阈值的关键帧,会为BA优化提供约束,但并不进行优化。
(7)删除冗余关键帧

KeyFrameCulling();

冗余关键帧指的是路标点的90%以上被3个以上的关键帧观察到。

相关文章:

十一连测day1

这次测试&#xff0c;是福建第三中学的某同学出的&#xff0c;感觉难度还行吧&#xff0c;今天我就浅谈一下这场比赛的时间分配与心得 打开题目&#xff0c;看到了T1&#xff0c;这题是一道计数题吧&#xff0c;感觉心态一下子就崩了&#xff0c;100%的数据点应该是组合数学容斥…

iOS 直播专题5-推流

常用的推流协议有: 协议内容RTP实时流传输协议,但不保证服务质量RTCPRTP数据流协议的一个姐妹协议,为RTP提供服务质量反馈SRTP & SRTCPRTP和RTCP的安全版本,提供数据加密、消息认证功能RTSP控制声音或影像的多媒体数据串流协议RTMPADOBE公司播放器与服务器之间多媒体数…

centos6.5-vsftp搭建

我的机子是默认是没有的vsftp。 yum install -y vsftp 创建账户专为ftp而生。useradd ftp01 更改账户不可登录系统。usermod -s /sbin/nologin ftp01 vsftp默认是可以匿名登录的&#xff0c;也是默认的端口&#xff0c;这些不安全选项都要修改&#xff01; anonymous_enableYES…

Linux04-文件系统权限与ACL权限

目录 一、文件系统权限 1.1、认识文件系统权限 1.2、管理文件系统权限 1.3、特殊权限 1.4、默认权限 二、ACL权限 2.1、ACL本质是文件系统的一个挂载选项 2.2、更改文件的ACL权限 2.3、设置文件和目录的默认ACL权限 Linux中的权限管理分为两种类型 用户自主访问控制&…

ORB_SLAM2帧Frame

在追踪线程的一开始就会创建一个帧 cv::Mat Tracking::GrabImageMonocular(const cv::Mat &im,const double &timestamp)构造函数 在构造函数中&#xff0c;会对特征点进行提取。 ExtractORB(0,imGray);特征点分配至网格 将图像划分为48*64的网格&#xff0c;然后将…

Servlet的基本架构

Servlet的基本架构&#xff1a; package test;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Serv…

ORACLE 用户权限管理

Oracle创建用户的语法&#xff1a; CREATE USER username IDENTIFIED BY password OR IDENTIFIED EXETERNALLY OR IDENTIFIED GLOBALLY AS CNuser [DEFAULT TABLESPACE tablespace] [TEMPORARY TABLESPACE temptablespace] [QUOTA [integer K[M] ] [UNLIMITED] ] ON tables…

iOS 直播专题6-流媒体服务器

常用的流媒体服务器有: nginx、SRS、BMS 这里主要介绍nginx、SRS 这里都用docker来运行流媒体服务器 docker 安装 下载Mac版docker stable 直接安装 注册一个docer账号直接登录SRS 安装 SRS guthub地址:https://github.com/ossrs/srs/ 启动上面安装的docker软件后,打开终端…

Linux05-进程管理

目录 一、进程 1.1、进程ID 1.2、列出进程 1.3、进程前后台 二、使用信号控制进程 三、以管理员身份注销用户&#xff08;踢掉在线用户&#xff09; 四、监控进程活动 4.1、负载平均值 4.2、实时进程监控 进程是已启动的可执行程序的运行中的实力。它由以下部分组成&a…

Mat常用赋值方式

参考https://blog.csdn.net/wanggao_1990/article/details/53264753 #include <iostream> #include <opencv2/opencv.hpp> #include <unordered_map> using namespace std; using namespace cv; int main(int argc,char** argv) {// 1Mat mat (Mat_<flo…

java modbus协议

概念 Modbus是一种串行通信协议&#xff0c;Modbus协议目前存在用于串口、以太网以及其他支持互联网协议的网络的版本。 大多数Modbus设备通信通过串口EIA-485物理层进行。 通讯格式 地址域功能码数据CRC校验(低字节在前)1字节1字节N字节2字节 在单片机硬件通讯串口行业&…

layui栅格布局问题

在使用layer.open弹出到窗口中&#xff0c;使用布局一直不起作用。 开始到写法如下, 目的是一行分成左右两块&#xff0c;比例为8:4等分。 <div class"layui-fluid"><div class"layui-row layui-col-space10"><div class"layui-col-md…

Unity3d载入外部图片文件

unity里的图片在生成时会压缩成资源文件&#xff0c;有时客户想自己放一些图片用unity显示&#xff0c;就必须载入外部图片。 大体思路&#xff1a;用Application.streamingAssetsPath或Application.dataPath来指定存放图片的相对路径。用DirectoryInfo获得目录。遍历后FileInf…

Linux06-服务、守护进程和systemd

目录 一、简介systemd 二、使用systemd 2.1、systemctl命令与systemd单元 2.2、控制系统服务 一、简介systemd RHEL6及以前&#xff0c;系统启动和服务器进程是由第一个进程 init 管理&#xff0c;init按顺序启动、启动慢。 RHEL7以后系统启动和服务器进程由 systemd系统和…

ORB_SLAM2回环检测

词典是特征点的描述子的集合&#xff0c;属于同一类特征的特征点的描述子组成单词。 在局部建图线程中&#xff0c;处理完一个关键帧后&#xff0c;会将其放入回环检测线程     在使用关键帧数据库搜索候选关键帧组&#xff08;DetectLoopCandidates&#xff09;的时候&…

nginx 启动 + uwsgi + django

https://www.cnblogs.com/chenice/p/6921727.html https://blog.csdn.net/Aaroun/article/details/78218131转载于:https://www.cnblogs.com/pythonClub/p/9746866.html

poj1741(树的点分治)

题目连接&#xff1a;POJ - 1741 看了好长时间才明白了点...... 网上讲解很多但感觉都不够详细。。。大概是太弱了吧-_-|| 学通了再回来写详解。。。 1 #include<iostream>2 #include<cstring>3 #include<cstdio>4 #include<algorithm>5 #define LL lo…

Android 串口通讯

概念 串行接口简称串口&#xff0c;也称串行通信接口或串行通讯接口&#xff08;通常指COM接口&#xff09;&#xff0c;是采用串行通信方式的扩展接口。串行接口&#xff08;Serial Interface&#xff09;是指数据一位一位地顺序传送。其特点是通信线路简单&#xff0c;只要一…

Linux07-OpenSSH

目录 一、使用SSH访问远程主机 1.1、什么是OpenSSH Secure Shell&#xff08;SSH&#xff09; 1.2、SSH主机密钥 二、配置基于SSH密钥的身份验证 2.1、基于SSH密钥的身份验证 2.2、自定义SSH服务配置 2.3、sftp传输文件 一、使用SSH访问远程主机 1.1、什么是OpenSSH Se…

ORB_SLAM2中的Sim3变换

对于双目、RGB-D相机&#xff0c;可获得深度&#xff0c;因此不存在尺度问题&#xff0c;因此Sim3中的尺度s1。 &#xff08;1&#xff09;通过词袋加速算法实现当前帧、闭环帧的特征点的匹配&#xff0c;建立闭环帧的路标点和当前帧的特征点间的联系。 &#xff08;2&#xff…

Ubuntu16.04 下的网易云出现网络异常、无法播放,界面无响应问题的统一解决

能够在Linux系统下体验到原生界面的网易云音乐是件不错的事情&#xff0c;但是它总是经常性的出现网络异常&#xff0c;界面无响应的问题 为了听歌的体验&#xff0c;进行深入探究&#xff1a; 首先通过终端启用网易云音乐&#xff1a;sudo netease-cloud-music 会得到网易云音…

SpringBoot 概念和起步

一、概念和由来 1、什么是 Spring Boot Spring Boot 的设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用特定方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。 Spring Boot 其实不是什么新的框架&#xff0c;它默认配置了很多框架的使用…

WKWebView Safari调试、JS互调、加载进度条、JS中alert、confirm、prompt

主要内容 Safari调试swift/OC与JS互调增加加载进度条支持JS中alert、confirm、prompt Safari调试 设置 —> safari --> 高级&#xff0c;开启JavaScript、网页检查器 打开Safari浏览器&#xff0c;选择调试的网页,同样在js里面可以断点调试: swift/OC与JS互调 这里…

CentOS7 打包RPM 升级OpenSSH8.3

目录 一、源码包 二、打包RPM 2.1、准备阶段 2.2、打包排错阶段 三、升级 漏扫设备发现OpenSSH有漏洞&#xff0c;需要升级到OpenSSH 8.1及以上版本&#xff0c;那么干脆就直接升级到发文时最新的版本&#xff0c;OpenSSH 8.3。做法是找到OpenSSH 8.3的源码包&#xff0c;…

步步为营-44-窗体之间传值--观察者模式

说明 :观察者模式又叫发布-订阅模式,其中又涉及到中介者模式 1 结构 2 创建Main窗体(中介者),ChildForm1(发布者),ChildForm2(订阅者),ChildForm3(订阅者), 2.1 ChildForm1中添加按钮,当按钮被点击是ChildForm2(订阅者),ChildForm3(订阅者),的文本框汇中获取信息 2.2 定义接口 …

java指令详解

Java是通过java虚拟机来装载和执行编译文件&#xff08;class文件&#xff09;的&#xff0c;java虚拟机通过命令java option 来启动&#xff0c;-option为虚拟机参数&#xff0c;通过这些参数可对虚拟机的运行状态进行调整. 一、如何查看参数列表: 虚拟机参数分为基本和扩展两…

wrs-arcface虹软人脸识别

前言 虹软人脸识别组件&#xff0c;支持活体识别、离线识别、图片人脸特征识别、图片是否同一人对比、相机人脸识别或对比,虹软免费版请使https://ext.dcloud.net.cn/plugin?id6084 功能 支持活体识别、离线识别图片人脸特征识别(年龄、性别、3DAngle)两张图片是否是同一人…

C++指针与引用的区别

&#xff08;1&#xff09;指针是一个变量&#xff0c;本身占有内存&#xff0c;内存中存储的是所指向对象的地址。引用是内存的别名。 &#xff08;2&#xff09;指针可以通过解引用的方式&#xff0c;取出所指向内存中的值。引用没有解引用。 &#xff08;3&#xff09;指针可…

Linux08-日志

目录 一、systemd的日志 1.1、sytemd-journald与systemd日志 1.2、systemd日志的持久化 二、系统常规日志 2.1、系统日志概述 2.2、查看系统日志文件 2.3、日志的轮转 2.4、分析系统日志 2.5、使用logger发送消息到日志 RHEL7的日志由2个服务负责记录&#xff0c;分别…

Java的小实验——各种测试以及说明

日期&#xff1a;2018.10.07 星期五 博客期&#xff1a;014 一、Java中的位运算 代码如下&#xff1a; 1 package Morts107;2 3 public class Test107 {4 public static void main(String[] args) {5 int z;6 z 13>>1;//00001101(13)---------------…