单眼视觉同步定位和映射

视觉同步定位和映射(VSLAM)是指在同时映射环境的同时计算相机的位置和方向的过程。该过程仅使用来自相机的可视输入。vslam的申请包括增强现实,机器人和自主驾驶。

此示例显示如何从单眼相机处理图像数据以构建室内环境的地图并估计相机的轨迹。该示例使用ORB-SLAM[1],这是一种基于特征的vslam算法。

要加快计算,您可以从中启用并行计算计算机视觉工具箱首选项对话框。打开计算机Vision Toolbox™首选项选项卡,在环境部分,点击喜好.然后选择计算机视觉的工具箱。

词汇表

在此示例中经常使用以下术语:

  • 关键框架:包含用于本地化和跟踪的提示的视频帧的子集。两个连续的关键帧通常涉及足够的视觉变化。

  • 地图积分:三维点列表,表示从关键帧重建的环境的映射。

  • 可辨证图:由关键帧作为节点组成的图表。如果它们共享通用地图点,则两个关键帧通过边沿连接。边缘的权重是共享地图点的数量。

  • 基本图:共视图的一个子图,只包含具有高权重的边,即更多的共享映射点。

  • 识别数据库:用于识别过去是否访问过某个地方的数据库。数据库存储基于特征输入包的可视文字到图像映射。它用于搜索视觉上与查询图像相似的图像。

ORB-SLAM概述

ORB-SLAM管道包括:

  • 地图初始化:ORB-SLAM通过从两个视频帧初始化三维点的贴图开始。通过基于二维球体特征对应的三角剖分计算三维点和相对相机姿态。

  • 追踪:一旦初始化了地图,对于每个新帧,通过将当前帧中的功能与最后一个关键帧中的特征匹配来估计相机姿势。通过跟踪本地地图来改进估计的相机姿势。

  • 本地映射:如果将其识别为关键帧,则使用当前帧创建新的3-D映射点。在此阶段,使用束调节来通过调整相机姿势和三维点来最小化重注错误。

  • 循环关闭:通过使用特征袋方法将其与所有先前的关键帧进行比较来检测每个关键帧的环路。一旦检测到循环闭合,姿势图被优化以改进所有关键帧的相机姿势。

下载并探索输入映像序列

在此示例中使用的数据来自Tum RGB-D基准[2]. 您可以使用web浏览器或运行以下代码将数据下载到临时目录:

BrienceOdloadURL =.'https://vision.in.tum.de/rgbd/dataset/freiburg3/rgbd_dataset_freiburg3_long_office_household.tgz';datafolder = fullfile(tempdir,“tum_rgbd_dataset”,filesep);选项= weboptions('超时',Inf);tgzFileName=[dataFolder,“fr3_office.tgz”];folderxists =存在(datafolder,“dir”);%在临时目录中创建一个文件夹以保存下载的文件如果〜Folderexists Mkdir(DataFolder);DISP('下载fr3_office.tgz(1.38 GB)。这个下载可能需要几分钟。)Websave(TGZFileName,BrienceOdlognull,选项);%提取下载文件的内容DISP('提取fr3_office.tgz(1.38 GB)......')Untar(TGzFilename,DataFolder);结尾

创建一个imageDatastore对象检查RGB图像。

imagefolder = [datafolder,'rgbd_dataset_freiburg3_long_office_house / rgb /'];imds = imageageataStore(imageFolder);%检查第一个图像CurrframeIdx = 1;Curri = ReadImage(IMDS,CurrFrameIDX);hemage = imshow(curli);

地图初始化

ORB-SLAM管道通过初始化一个具有3-D世界点的地图来开始。这一步骤至关重要,对最终SLAM结果的准确性产生重大影响。使用初始ORB特征点对应关系matchfeatures.在一对图像之间。找到对应文后,使用两个几何变换模型来建立映射初始化:

  • 众同情:如果场景是平面的,则相同的投影转换是描述特征点对应的更好选择。

  • 基础矩阵:如果场景是非平面的,则必须使用基本矩阵。

可以使用相同的定址和基本矩阵estimateGeometricTransform.estismsfundamentalmatrix.,分别。采用产生较小重投影误差的模型估计两帧间的相对旋转和平移relativecamerapose..由于RGB图像由不提供深度信息的单眼摄像机拍摄,因此只能恢复到特定比例因子的相对转换。

给定两个图像中的相对相机姿势和匹配的特征点,使用匹配点的3-D位置使用三角化函数。当一个三角形地图点位于两个相机的前面,当它的重投影误差很低,并且当这个点的两个视图的视差足够大时,它是有效的。

%为重现性设置随机种子RNG(0);%创建摄像机对象以存储相机内部参数。%可在以下页面找到数据集的内部函数:%https://vision.in.tum.de/data/datasets/rgbd-dataset/file_formats.%介绍数据集中的图像已毫无变形,因此存在%不需要指定失真系数。focalLength = [535.4, 539.2];以像素为单位林城= [320.1,247.6];以像素为单位图像智能=尺寸(CURI,[1 2]);以像素为单位内在=摄像石(FocalLength,Principalpoint,Imageize);%检测和提取ORB功能[装饰,前视图] = HelperDetectAddExtractFeatures(Curli);CurrFrameIDX = CurrFrameIDX + 1;Firsti = Curli;%保留第一帧ismapinitialized = false;%映射初始化循环虽然〜isMapInitialized && hasdata(IMDS)Curri = ReadImage(IMDS,CurrFrameIDX);[Currfeatures,Currpoints] = HelperDetectAndExtractFeatures(Curli);CurrFrameIDX = CurrFrameIDX + 1;%找到推定的功能匹配indexPairs = MatchFeatures(预成分,Currfeatures,'独特',真的,......'maxratio',0.7,“MatchThreshold”, 70);%如果没有找到足够的匹配,请检查下一帧minmatches = 100;如果尺寸(indexpaire,1)继续结尾preMatchedPoints = prePoints (indexPairs (: 1):);currMatchedPoints = currPoints (indexPairs (:, 2):);%计算同众法和评估重建[tformh,scounth,Inliersidxh] = HelperComputeHomography(PrematchedPoints,CurrmatchedPoints);%计算基本矩阵和评估重构[tformf,scoundf,Inliersidxf] =升迁普通邮奖amatrix(prematchedpoints,currmatchedpoints);%基于启发式选择模型比率=记分/(记分+得分);ratiothreshold = 0.45;如果比率> ratiothreshold InliertFormidx = InliersidXH;tform = tformh;别的InliertFormIdx = InliersidXF;tform = tformf;结尾%按比例计算相机位置。用一半的时间减少计算的%点InlierPrepoints = prematchedPoints(InliertFormIdx);InlierCurropits = CurrMatchedPoints(InliertFormIdx);[Relorient,Relloc,ValudFraction] = RelativeCamerapose(Tform,Intrinsics,......InlierPropoints(1:2:结束),InlierCurroports(1:2:结束));%如果没有找到足够的inliers,则移动到下一个帧如果有效期<0.7 ||numel(尺寸(Relorient))== 3继续结尾%三角化两个视图以获得3-D映射点相关= rigid3d(Relorient,Relloc);[IsValid,XYZWorldPoints,InliertriangulationIdX] = HelpertriangulateTwoframe(......rigid3d,有关,inlierprepoints,Inliercurrports,内在机构);如果〜Isvalid.继续结尾%获得两个关键帧中的原始功能索引indexPairs = IndexPairs(InliertFormIdx(InliertriangulationIDX),:);ismapinitialized = true;DISP(['用框架1和框架初始化映射,num2str(currFrameIdx-1)])结尾%映射初始化循环
使用第1帧和第42帧初始化贴图
如果ismapinitialized关闭(Hemage.Parent.Parent);%关闭前一个数字%显示匹配的特征hfeature = ShowMatchedFeatures(第一,Curli,Prepoints(IndexPairs(:,1)),......FurrPoints(IndexPairs(:,2)),'剪辑');别的错误(“无法初始化映射。”结尾

存储初始关键帧和映射点

使用两个框架初始化地图后,可以使用imageviewset.helpermappointset.要存储两个关键帧和相应的地图点:

  • imageviewset.存储关键帧及其属性,例如球体描述符、特征点和摄影机姿势,以及关键帧之间的连接,例如特征点匹配和相对摄影机姿势。相机的姿势存储为rigid3d.目的。

  • helpermappointset.存储地图点及其属性,例如3-D位置,视图方向,代表性ORB描述符以及可以观察地图点的距离范围。地图点对象还将3-D存储到二维投影对应关系中:在密钥帧中观察到哪个映射点,并且该键帧观察地图点。

%创建一个空的ImageViewset对象以存储密钥帧vsetkeyframs = imageviewset;%创建一个空的helperMapPointSet对象来存储3D地图点mappointset = helpermappointset;%添加第一关键帧。将相机与第一个相关联沿z轴定向的原点处的%键帧priviewid = 1;vsetkeyframes = addview(vsetKeyFrames,PreviewID,Rigid3D,“点”,前景,......'特征',装饰.Features);%添加第二个关键帧currviewid = 2;vsetkeyframes = addview(vSetKeyFrames,curviewId,ripled,“点”,curports,......'特征',currfeatures.features);%在第一和第二关键帧之间添加连接vSetKeyFrames = addConnection(vSetKeyFrames, preViewId, currViewId, relPose,“火柴”,indexpairs);%添加3-D映射点[mappointet,newpointidx] = addmappoint(mappointset,xyzworldpoints);%添加地图点的观察前置位置=前置位置;currLocations=currPoints.Location;预标定=预标定刻度;currScales=currPoints.Scale;%添加与第一关键帧中的地图点对应的图像点mappointet = addobservation(mappointset,newpointidx,previewid,indexpaess(:1),......prelations(IndexPairs(:,1),:),预分析(IndexPairs(:,1)));%添加与第二关键帧中的地图点对应的图像点mappointet = addobservation(mappointset,newpointidx,currviewid,indexPairs(:,2),......currLocations (indexPairs (: 2):), currScales (indexPairs (:, 2)));

优化和可视化初始重建

使用初始重建使用Bundleadjustment.,它优化了摄影机姿势和世界点,以最小化整体重投影错误。细化后,地图点的属性(包括三维位置、视图方向和深度范围)将更新并存储在中mappointset..您可以使用HelpervisualizeMotionAndandstructure.可视化地图点和相机位置。

%在前两个关键帧上运行完整的bundle调整曲目= findtracks(vsetkeyframs);cameraposes =姿势(vsetkeyframes);[RefiningPoints,Refiningabsposs] = BundleAdjustment(XYZWorldPoints,轨道,......Cameraposes,内在机构,'filedviewids',1,......'obessundistorted',真的,'absolutetolerance',1e-7,......'relativetolerance',1e-15,'maxIteration',50);%缩放地图和相机姿势使用中值的地图点中位数=中位数(vecnorm(RefiningPoints。));RefiningPoints = RefiningPoints /中年;Refiningabsposs.absolutepose(currviewid).translation =......Refiningabsposs.absolutepose(currviewid)。翻译/中美型;resime.ranslation = resimed.ranslation /中学部;%更新带有精细姿势的关键帧vsetKeyFrames = UpdateView(vsetKeyFrames,Refiningabsposs);vsetKeyFrames = UpdateConnection(VSetKeyFrames,PreviewID,CurviewID,有用);%更新使用精细位置的地图点mappointset = UpdatElocation(MappointSet,RefiningPoints);%更新视图方向和深度mappointet = updateViewandRange(Mappointset,vsetKeyFrames.views,newpointidx);%可视化当前帧中的匹配功能关闭(hfeature.parent.parent);Featureplot = HelpervisualizeMatchedFeatures(Curri,CurrPoints(IndexPairs(:,2)));

%可视化初始映射点和相机轨迹mapplot = helpervisualizemotionandandanduredulture(vsetkeyframes,mappointset);%显示传奇ShowLegend(Mapplot);

追踪

使用每个帧执行跟踪处理,并确定何时插入新密钥帧。为简化此示例,我们将在找到循环关闭后终止跟踪过程。

当前关键帧的%视角currKeyFrameId=currViewId;最后一个关键框架的%视角LastKeyFrameID = CurviewId;%具有最多共可见的参考关键帧的ViewId%使用当前关键帧映射点RefKeyFrameID = CurviewID;输入图像序列中最后一个键帧的%索引lastKeyFrameIdx = currFrameIdx - 1;输入图像序列中所有关键帧的%索引AddatedFramesIdx = [1;lastkeyframeidx];isloopclosed = false;

每个帧都处理如下:

  1. 为每个新帧提取ORB功能,然后匹配(使用matchfeatures.),最后一个关键帧中的特征具有已知的相应三维贴图点。

  2. 使用Perspective-N点算法估算相机姿势estismsworldcamerapose.

  3. 给定相机姿势,将最后一个关键帧观察到当前帧观察的地图点,并搜索使用的特征对应HelpermatchFeaturesinradius.

  4. 在当前框架中使用3-D至2-D对应关系,通过执行仅执行仅动作的捆绑调整,优化相机姿势BundleadjustmentMotion.

  5. 将本地地图投影到当前帧中以搜索更多功能对应关系HelpermatchFeaturesinradius.并再次优化相机姿势BundleadjustmentMotion.

  6. 跟踪的最后一步是确定当前帧是否是新密钥帧。如果当前帧是关键帧,请继续本地映射过程。否则,开始追踪对于下一个框架。

%主回路虽然~isLoopClosed&&hasdata(imds)currI=readimage(imds,currFrameIdx)[currFeatures,currPoints]=helperDetectAndExtractFeatures(currI);%跟踪最后一个关键帧%mappointsidx:在当前帧中观察到的地图点的索引%featuredx:相应特征点的指标%当前帧[currPose,mapPointsIdx,featureIdx]=helperTrackLastKeyFrame(mapPointSet,......vsetkeyframs.views,currfeatures,curpoints,lastKeyFrameID,内在机构);%跟踪本地地图%refKeyFrameID:查看最多的参考密钥框架具有当前帧的%共同可见映射点%localKeyFrameID:查看当前帧的连接密钥帧的视角[refKeyFrameID,LocalKeyFrameID,施加,mappointsidx,featuredIdx] =......HelperTrackLocalMap(MappointSet,VSetKeyFrames,Mappointsidx,......Featureidx,施法,Curfeatures,Currpoints,内在函数);%检查当前帧是否为关键帧。%满足以下两个条件的帧为关键帧:%1.自上次关键框架或者以来已经通过了至少20帧%当前帧轨道轨道少于80个地图点%2.当前帧跟踪的地图点少于90%参考密钥框架跟踪的%点ISKeyFrame = HelperisKeyFrame(Mappointset,RefKeyFrameID,LastKeyFrameIdx,......currFrameIdx mapPointsIdx);%可视化匹配的功能updateplot(featureplot,curli,currpoints(featuredidx));如果〜ISKeyFrame CurrFrameIDX = CurrFrameIDX + 1;继续结尾%更新当前密钥帧IDCurrkeyFrameID = CurrkeyFrameID + 1;

本地映射

对每个关键帧执行本地映射。确定新密钥帧时,将其添加到关键帧并更新由新密钥帧观察到的地图点的属性。为了保证mappointset.包含尽可能少的异常值,必须在至少3个关键帧中观察到有效的映射点。

通过在当前密钥框架及其连接的关键帧中三角形结构点来创建新的地图点。对于当前密钥帧中的每个无与伦比的特征点,使用连接的关键帧中的其他无与伦比点搜索匹配matchfeatures..局部束调整优化当前关键帧的位姿、连接关键帧的位姿以及在这些关键帧中观察到的所有地图点。

%添加新密钥框架[mappointset,vsetkeyframes] = helperaddnewkeyframe(mappointset,vsetkeyframes,......施归,Currfeatores,Curpopitts,Mappointsidx,FeaturedIDX,LocalKeyFrameID);%更新视图方向和深度mappointet = updateViewandRange(Mappointset,vsetKeyFrames.views,mappointsidx);%删除在少于3个关键框架中观察到的异常值地图点mapPointSet = helperCullRecentMapPoints(mapPointSet, vSetKeyFrames, newPointIdx);%通过三角测量创建新的地图点[mappointet,vsetkeyframes,newpointIdx] = helpercreateNewmappoints(mappointset,vsetkeyframes,......currKeyFrameId intrinsic);%本地捆绑调整[mapPointSet,vSetKeyFrames]=helperLocalBundleAdjustment(mapPointSet,vSetKeyFrames,......currKeyFrameId intrinsic);可视化3D世界点和摄像机轨迹updateplot(mapplot,vsetkeyframes,mappointset);

循环关闭

循环闭合步骤采用本地映射过程处理的当前密钥帧,并尝试检测和关闭环路。使用袋式方法执行循环检测。视觉词汇代表为a巴戈菲特酒店通过调用DataSet中的大量图像中提取的冲浪描述符脱机,通过调用:

BAG = BAGOFFEature(IMDS,'Corextractor',@HelpersurfefeatureextractorFunction);

在哪里IMDS.是一个imageDatastore存储培训图像和elplersurfeepureextractorfunction是SURF特征提取函数。看到基于视觉词包的图像检索了解更多信息。

循环关闭过程递增地构建数据库,表示为一个数据库invertedimageIndex.对象,基于冲浪功能的袋子存储视觉字到图像映射。通过在视觉上类似于当前密钥帧的数据库中查询图像中的图像来识别循环候选evaluateMageretrieval..如果它未连接到最后一个关键帧,并且其三个邻居键帧是循环候选的,则候选键帧是有效的。

当找到有效的循环候选者时,使用与使用的策略相同的策略计算环候选帧和当前密钥帧之间的相对姿势追踪过程。然后使用相对姿势和更新添加循环连接mappointset.vsetKeyframs.

%初始化循环关闭数据库如果CurrEid==3%加载脱机创建的功能数据bofdata = load('bagoffeaturesdata.mat');LoopDatabase = InvertedImageIndex(Bofdata.bof);LoopCandIdates = [1;2];在创建某些关键帧后%检查循环关闭eleesifcurrKeyFrameId > 20%检测可能的循环闭合密钥框架候选[Isdetected,ValidLoopCandIdates] = HelperCheckLoopClosure(vsetKeyFrames,CurrkeyFrameID,......LoopDatabase,Curli,LoopcandIdates);如果isdetected.%添加循环闭合连接[isLoopClosed,mapPointSet,vSetKeyFrames]=helperAddLoopConnections(......mapPointSet、vSetKeyFrames、ValidLoop、,......CurrkeyFrameID,Currfeatures,Curpopits,内在机构);结尾结尾%如果未检测到循环关闭,则将图像添加到数据库中如果~isLoopClosed currds=imageDatastore(imds.Files{currFrameIdx});addImages(循环数据库、currds、,'verbose', 错误的);LoopCandIdates = [LoopCandIdates;CurrkeyFrameID];%#OK 结尾%更新ID和索引lastKeyFrameID = CurkeyFrameID;lastkeyframebidx = currframeidx;AddatedFramesIDX = [已添加FramesIdx;CurrframeIDX];%#OK CurrFrameIDX = CurrFrameIDX + 1;结尾%循环的末端

在关键帧:3和123之间添加循环边在关键帧:1和123之间添加循环边在关键帧:2和123之间添加循环边在关键帧:4和123之间添加循环边在关键帧:5和123之间添加循环边在关键帧:6和123之间添加循环边在关键帧:7和123之间添加循环边在关键帧:8和在关键帧:9和123之间添加的123循环边在关键帧:10和123之间添加的123循环边

最后,在基本图中执行姿势图优化vsetKeyframs.纠正旋转和翻译中的漂移。通过删除与少于的连接来创建基本图形minnummatches.匹配在可执行性图中。

优化姿势minnummatches = 40;vsetkeyframesoptim =优化邮件(vsetKeyFrames,minnummatches,“宽容”,1e-16,'verbose', 真的);
迭代1,剩余误差0.036293迭代2,剩余误差0.036189迭代3,剩余误差0.036189迭代4,剩余误差0.036189迭代5,剩余误差0.036189迭代6,剩余误差0.036189迭代7,剩余误差0.036189求解器停止,因为功能值的变化是停止的小于指定的功能公差。
%绘制优化的相机轨迹优化=姿势(vsetkeyFramesoptim);plotOptimizedTrajection(Mapplot,优化)%更新图例ShowLegend(Mapplot);

与地面真相比较

您可以将优化的摄像机轨迹与地面真相进行比较,以评估ORB-SLAM的准确性。下载的数据包含一个Troundtruth.txt.存储每个帧的摄像机姿势的地面真实的文件。数据已以MAT文件的形式保存。您还可以计算轨迹估计的根均方误差(RMSE)。

%负荷地面真相GTR数据=负载('orbslamgroundtruth.mat');gtruth = gtruthdata.gtruth;%绘制实际的相机轨迹plotactualtrajectory(mapplot,gtruth(附加帧),优化);%显示传奇ShowLegend(Mapplot);

%评估跟踪准确性HelperestimateTrajectoryError(GTRUTH(已添加FRAMESIDX),优化);
关键帧轨迹的绝对RMSE(M):0.098218

这结论是如何构建室内环境的地图并使用ORB-SLAM估算相机轨迹的概述。

万博1manbetx支持功能

简短的辅助功能包括在下面。更大的函数包含在单独的文件中。

HelperaddloopConections.在当前关键帧和有效循环候选之间添加连接。

HelperaddnewKeyframe.将关键框架添加到键框架集。

Helpercheckloopflosure.通过从数据库中检索视觉相似的图像来检测循环候选密钥帧。

HelpercreateNewmappoints.通过三角测量创建新的地图点。

HelperfindProjectedPointsInimage.检查投影的世界点是否在图像内。

helperhamming距离计算两组二进制特征向量之间的汉明距离。

Helperlocalbundleadjustment.优化当前关键框架的姿势和AdraTrounding场景的地图。

helpermappointset.管理可视化SLAM的地图数据。

HelpermatchFeaturesinradius.匹配半径内的特征。

allowselectstronconnections.选择具有多于指定数量的匹配项的强连接。

elplersurfeepureextractorfunction实现bagfeatures中使用的SURF特征提取。

Helpertracklastkeyframe.通过跟踪最后一个关键框架来估计当前的相机姿势。

Helpertracklocalmap.通过跟踪局部贴图优化当前摄影机姿势。

helperVisualizeMatchedFeatures在一个框架中显示匹配的特征。

HelpervisualizeMotionAndandstructure.显示地图点和相机轨迹。

HelperdetectandExtractFeatures.从图像中检测、提取和提取特征。

功能[功能,有效点] = HelperDetectAndExtractFeatures(IRGB,Varargin)Scalefactor = 1.2;numlevels = 8;Numpoints = 1000;%在本例中,图像已经不失真。总的来说%工作流中,取消注释以下代码以取消对图像的干扰。%如果nargin>1%内在= varargin {1};% 结尾%Irgb = untostortimage(Irgb,内在);%检测ORB功能IGRAY = RGB2GRAY(IRGB);点= detectorbfeatures(Igay,'比例因子', 比例因子,'numlevels',numlevels);%选择一个功能子集,均匀分布在整个图像中点= SelectUniform(点,Numpoints,大小(Igray,1:2));%提取特征[features, validPoints] = extractFeatures(Igray, points);结尾

HelperhomographyScore.计算单应性并评估重建。

功能[H,Score,InliersIndex] = HelperComputeHomography(MatchedPoints1,MatchedPoints2)[H,InLierpoints1,InLierpoints2] = eStimateGeometricTransform(......matchedpoints1,matchedpoints2,'投影'......'maxnumtrial'1 e3,'maxdistance',4,'置信度',90);[〜,InliersIndex] =相交(matchedpoints1.location,......Inlierpoints1.Location,'排''稳定的');locations1 = inlierPoints1.Location;locations2 = Inlierpoints2.Location;XY1in2 = TransformPointSforward(H,Locations1);XY2IN1 = TransformPointsInverse(H,Locations2);error1in2 = sum((locations2  -  xy1in2)。^ 2,2);ERROR2IN1 = SUM((LOCATIONS1  -  XY2IN1)。^ 2,2);OuttiAlthreshold = 6;得分= sum(max(OutlierThreshold-error1in2,0))+......sum (max (outlierThreshold-error2in1, 0));结尾

HelperfundamentalMatrixScore.计算基本矩阵并评估重建。

功能[f,score,InliersIndex] = HelperComputeFundamentalMatrix(matchedPoints1,matchedpoints2)[f,InlierslogicalIndex] = estImationFundamentalMatrix(......matchedpoints1,matchedpoints2,'方法''ransac'......“NumTrials”1 e3,'distancethreshold', 0.01);inlierPoints1 = matchedPoints1 (inliersLogicalIndex);inlierPoints2 = matchedPoints2 (inliersLogicalIndex);inliersIndex =找到(inliersLogicalIndex);locations1 = inlierPoints1.Location;locations2 = Inlierpoints2.Location;%点到极线的距离linein1 = epipolarline(f',位置2);ERROR2IN1 =(SUM([LOCATIONS1,SUNATIONS1(LOCATIONS1,1),1)]。* LINEIN1,2))。^ 2......./总和(LineIn1(:,1:2)。^ 2,2);linein2 = epipolarline(f,locations1);ERROR1IN2 =(SUM([LOCATIONS2,SUNATIONS2)]。* LINEIN2,2))。^ 2....../和(第2行(:,1:2)。^2,2);异常阈值=4;分数=总和(最大值(离群值阈值-error1in2,0))+......sum (max (outlierThreshold-error2in1, 0));结尾

HelpertriangulatetTeTwoframe.三角化两个框架才能初始化地图。

功能[ISVALID,XYZPOINTS,INLILIDX] = HelpertriangulateTwoframe(......pose1,pose2,matchedpoints1,matchedpoints2,内在函数)[r1,t1] = cameraposetoextrinsics(pose1.rotation,pose1.translation);Cammatrix1 = Cameramatrix(内在机构,R1,T1);[R2,T2] = CameraPoSetoExtrinsics(POSE2.ROTATION,POSE2.Translation);Cammatrix2 = Cameramatrix(内在,R2,T2);[XYZPOINTS,REPOURNEEREERRORS] =三角形(匹配点1,......MatchedPoints2,Cammatrix1,Cammatrix2);通过查看方向和重注错误%过滤点minReprojError=1;inlierIdx=xyzPoints(:,3)>0&reprojectionErrors%一个很好的双视图,具有重要的视差ray1=xyzPoints-位置1.平移;ray2=xyzPoints-位置2.平移;余角=和(ray1.*ray2,2)。/(vecnorm(ray1,2,2)。*vecnorm(ray2,2));%检查视差minparallax = 3;%以度为单位isValid=all(cosAngle0);结尾

HelperiskeyFrame.检查帧是否是关键帧。

功能iskeyframe = helperiskeyframe(mappoints,......RefKeyFrameID,LastKeyFrameIndex,CurrframeIndex,MappointSindices)NumpointSrefKeyFrame = Numel(GetMappointIndex(MapPoints,RefKeyFrameID));从上次键帧插入传递%超过20帧toomanynonkeyframes = currframeIndex> = lastKeyFrameIndex + 20;%跟踪少于80个地图点toofewmappinoints = numel(mappointsindices)<80;%跟踪的地图点少于用户跟踪的点的90%%参考密钥框架toofewtrackedpoints = numel(mappointsindices)<0.9 * numpointsrefkeyframe;ISKEYFRAME =(TOOMANYNONKEYFRAMES || TOOFEWMAPPOINTS)&& toofewtrackedpoints;结尾

HelpercullRecentmappoints.剔除最近添加了地图积分。

功能mapPoints = helperCullRecentMapPoints(mapPoints, keyFrames, newPointIdx)为了i = 1:numel(newpointidx)idx = newpointidx(i);%如果在少于3个关键框架中观察到地图点,请将其丢弃如果numel(mapPoints.Observations{idx,1})<3&&......max(mappoints.observations {idx,1})结尾结尾结尾

HelperestimateTrajectoryError.计算跟踪错误。

功能RMSE = HelperestimateTrajectoryError(GTRUTH,Camerapse)位置= VertCAT(Camerapose.absolutePose.Ranslation);glocations = Vertcat(gtruth.translation);Scale =中位数(Vecnorm(壁垒,2,2))/中位数(Vecnorm(位置,2,2));ScaleDlocations =位置*比例;RMSE = SQRT(平均值(SUMEDLOCATIONS  - 绑持)。^ 2,2)));DISP(['关键帧轨迹的绝对RMSE(m):',num2str(rmse)];结尾

参考

[1] Mur-Artal,Raul,Jose Maria Martiinez Montiel和Juan D. Tardos。“ORB-SLAM:一种多功能和准确的单眼猛击系统。”IEEE机器人学报2015年11月31日,第5号,第1147-116页。

[2] Sturm, Jürgen, Nikolas Engelhard, Felix Endres, Wolfram Burgard和Daniel Cremers。“评估RGB-D SLAM系统的基准”。在IEEE / RSJ智能机器人和系统会议的诉讼程序,pp。573-580,2012。