主要内容

このペ,ジの翻訳は最新ではありません。ここをクリックして,英語の最新版を参照してください。

単眼の视觉同步定位和映射

视觉同步定位和映射(vSLAM)とは,環境のマッピングを行うのと同時に,周囲に対するカメラの位置と向きを計算する処理を意味します。この処理では,カメラからの視覚的入力のみを使用します。vSLAMの用途には、拡張現実、ロボット工学、自動運転などがあります。asscociated

この例では,単眼カメラのイメージデータを処理して,屋内環境マップをビルドし,カメラの軌跡を推定する方法を説明します。例では,特徴ベ,スのvSLAMアルゴリズムであるORB-SLAM[1]を使用します。

計算を高速化するために,计算机视觉工具箱の基本設定ダ@ @アログボックスで並列計算を有効にできます。计算机视觉工具箱™ の基本設定を開くには、[ホ,ム]タブの[環境]セクションで[基本設定]をクリックします。そして[计算机视觉工具箱]を選択します。

用語

この例では次の用語をよく使用します。

  • キ,フレ,ム:位置推定とトラッキングのキュ,を含む,ビデオフレ,ムのサブセット。。

  • マップ点:キフレムから再構成した環境のマップを表す3次元点のリスト。

  • 共视度グラフ:ノ,ドとしてのキ,フレ,ムで構成されるグラフ。2 .のキ,フレ,ムが共通のマップ点を共有している場合,エッジにより接続されます。エッジの重みは,共有されているマップ点の数です。

  • 必备グラフ:重みが大きい,つまり共有されているマップ点が多いエッジのみを含む,Covisibilityグラフの部分グラフ。

  • 場所認識デ,タベ,ス:ある場所を過去に訪れたことがあるかどうかを認識するために使用されるデ,タベ,ス。このデ,タベ,スは、入力された bag of features に基づく、ビジュアル ワードからイメージへのマッピングを格納します。クエリ イメージと視覚的に類似したイメージを探索するために使用されます。

Orb-slamの概要

Orb-slamのパaaplプラaaplンには次が含まれます。

  • マップの初期化: orb-slamはまず,2のビデオフレムから3次元点のマップを初期化します。2次元ORB特徴の対応関係に基づく三角形分割を使用して,3次元点と相対カメラ姿勢が計算されます。

  • トラッキング:マップが初期化された後は,新しいフレームごとに,現在のフレームの特徴を最後のキーフレームの特徴とマッチングすることにより,カメラ姿勢が推定されます。推定されたカメラ姿勢は,局所マップのトラッキングにより調整されます。

  • 局所マッピング:現在のフレームがキーフレームとして識別された場合に,そのフレームを使用して,新しい3次元マップ点を作成します。この段階で,カメラ姿勢と3次元点を調整することにより,バンドル調整を使用して再投影誤差を最小化します。

  • ル,プクロ,ジャ: bag-of-featuresアプローチを使用して,キーフレームごとにそれまでのすべてのキーフレームと比較することで,ループを検出します。ループクロージャが検出されると姿勢グラフが最適化され,すべてのキーフレームのカメラ姿勢を調整します。

入力メジシケンスのダウンロドと確認

この例で使用するデ,タはTUM RGB-D基准[2]のものです。Webブラウザーを使用するか,次のコードを実行することで,データを一時ディレクトリにダウンロードできます。

baseDownloadURL =“https://vision.in.tum.de/rgbd/dataset/freiburg3/rgbd_dataset_freiburg3_long_office_household.tgz”;dataFolder = fullfile(tempdir,“tum_rgbd_dataset”, filesep);选项= weboptions(“超时”、正);tgzFileName =[数据文件夹,“fr3_office.tgz”];folderExists = exist(数据文件夹“dir”);在临时目录中创建一个文件夹来保存下载的文件如果~ folderExists mkdir (dataFolder);disp (“下载fr3_office。tgz (1.38 GB)。下载过程可能需要几分钟。”) websave(tgzFileName, baseDownloadURL,选项);提取下载文件的内容disp (“提取fr3_office。tgz (1.38 GB)…') untar(tgzFileName, dataFolder);结束

imageDatastoreオブジェクトを作成して,rgbメジを検査します。

imageFolder =[数据文件夹,“rgbd_dataset_freiburg3_long_office_household / rgb /”];imds = imageDatastore(imageFolder);检查第一个图像currFrameIdx = 1;currI = readimage(imds, currFrameIdx);himage = imshow(currI);

マップの初期化

Orb-slamパプランではまず,3次元ワルド座標点をもマップを初期化します。このステップは重要であり,slamの最終結果の精度に大きく影響します。2 .matchFeaturesを使用して,初期のorb特徴点の対応関係を求めます。対応関係を求めた後,2の幾何学的変換モデルを使用して,マップの初期化を設定します。

  • ホモグラフィ:シ,ンが平面の場合,特徴点の対応関係を表すには,ホモグラフィ射影変換の方が適しています。

  • 基礎行列:シ,ンが平面ではない場合,代わりに基礎行列を使用しなければなりません。

ホモグラフィと基礎行列はそれぞれ,estimateGeometricTransform2DおよびestimateFundamentalMatrixを使用して計算できます。再投影誤差がより少なかったモデルを選択し,relativeCameraPoseを使用して,2のフレ。深さの情報を提供しない単眼カメラからRGBイメージを取得しているため,相対並進はある程度のスケール係数までしか復元できません。

2 .由三角形组成的を使用して,特徴点の3次元での位置を決定します。三角形分割されたマップ点は,それが両方のカメラの正面にある場合,再投影誤差が小さい場合,およびその点の2つのビューのパララックスが十分に大きい場合には有効です。

为重现性设置随机种子rng (0);创建一个cameraIntrinsics对象来存储相机的内在参数。数据集的intrinsic可以在下面的页面中找到:% https://vision.in.tum.de/data/datasets/rgbd-dataset/file_formats注意,数据集中的图像已经是未扭曲的,因此有%不需要指定失真系数。focalLength = [535.4, 539.2];%,以像素为单位principalPoint = [320.1, 247.6];%,以像素为单位imageSize = size(currI,[1 2]);%,以像素为单位intrinsic = cameraIntrinsics(focalLength, principalPoint, imageSize);检测和提取ORB特征scaleFactor = 1.2;numLevels = 8;numPoints = 1000;[preFeatures, prePoints] = helperDetectAndExtractFeatures(currI, scaleFactor, numLevels, numPoints);currFrameIdx = currFrameIdx + 1;firstI = currI;保留第一帧isMapInitialized = false;%映射初始化循环~isMapInitialized && currFrameIdx < numel(imds. files) currI = readimage(imds, currFrameIdx);[currFeatures, currPoints] = helperDetectAndExtractFeatures(currI, scaleFactor, numLevels, numPoints);currFrameIdx = currFrameIdx + 1;查找假定的特征匹配indexPairs = matchFeatures(preFeatures, currFeatures,“独特的”,真的,...“MaxRatio”, 0.9,“MatchThreshold”, 40);preMatchedPoints = prePoints(indexPairs(:,1),:);currMatchedPoints = currPoints(indexPairs(:,2),:);如果没有找到足够的匹配,检查下一帧minMatches = 100;如果size(indexPairs, 1) < minMatches . size(indexPairs, 1继续结束preMatchedPoints = prePoints(indexPairs(:,1),:);currMatchedPoints = currPoints(indexPairs(:,2),:);计算单应性和评估重建[tformH, score, inliersIdxH] = helperComputeHomography(preMatchedPoints, currMatchedPoints);计算基本矩阵并评估重建[tformF, scoreF, inliersIdxF] = helperComputeFundamentalMatrix(preMatchedPoints, currMatchedPoints);根据启发式选择模型ratio = score /(score + scoreF);ratioThreshold = 0.45;如果ratio > ratioThreshold inliertlikox = inliersIdxH;tform = tformH;其他的inliersIdxF;tform = tformF;结束按比例计算相机位置。使用一半的%以减少计算量inlierPrePoints =预匹配点(inliertlikox);inlierCurrPoints = currMatchedPoints(inliertlikox);[relOrient, relLoc, validFraction] = relativeCameraPose(tform, intrinsic,...inlierPrePoints(1:2)结束,inlierCurrPoints(1:2:结束));%如果没有找到足够的内线,移动到下一帧如果validFraction < 0.9 || number (size(relOrient))==3继续结束三角化两个视图以获得3-D地图点relPose = rigid3d(relOrient, relLoc);minParallax = 1;%(度)[isValid, xyzWorldPoints, inlierTriangulationIdx] = helperTriangulateTwoFrames(...rigid3d, relPose, inlierPrePoints, inlierCurrPoints, intrinsic, minParallax);如果~ isValid继续结束获取两个关键帧中特征的原始索引indexPairs = indexPairs(inliertx (inlierTriangulationIdx),:);isMapInitialized = true;disp (['用帧1和帧初始化的映射'num2str (currFrameIdx-1)])结束映射初始化循环结束
用帧1和帧26初始化的映射
如果isMapInitialized关闭(himage.Parent.Parent);关闭上一个图形显示匹配的特征hfeature = showMatchedFeatures(firstI, currI, prePoints(indexPairs(:,1)),...currPoints (indexPairs (:, 2)),“蒙太奇”);其他的错误(“无法初始化地图。”结束

初期キ,フレ,ムとマップ点の格納

2 .のフレ,ムを使用してマップを初期化した後で,imageviewsetworldpointset,およびhelperViewDirectionAndDepthを使用して,この2のキフレムとこれらに対応するマップ点を格納できます。

  • imageviewsetは,キーフレームとその属性(ORB記述子など),特徴点とカメラ姿勢,およびキーフレーム間の関係(特徴点の一致,相対カメラ姿勢など)を格納します。また,姿勢グラフを作成および更新します。オドメトリエッジの絶対カメラ姿勢と相対カメラ姿勢は,rigid3dオブジェクトとして保存されます。ル,プクロ,ジャエッジの相対カメラ姿勢は,affine3dオブジェクトとして保存されます。

  • worldpointsetは,マップ点の3次元の位置と,3次元から2次元への投影の対応関係,つまりどのマップ点がキーフレームで観測され,どのキーフレームでマップ点を観測するかという関係も格納します。

  • helperViewDirectionAndDepthは,マップ点の他の属性(平均的なビューの方向,代表的なORB記述子,およびマップ点を観測可能な距離範囲など)を格納します。

创建一个空的imageviewset对象来存储关键帧vSetKeyFrames =图像视图;创建一个空的worldpointset对象来存储三维地图点mapPointSet = worldpointset;创建一个helperViewDirectionAndDepth对象来存储视图的方向和深度directionAndDepth = helperViewDirectionAndDepth(size(xyzWorldPoints, 1));添加第一个关键帧。将相机与第一个相关联%关键帧在原点,沿z轴方向preViewId = 1;vSetKeyFrames = addView(vSetKeyFrames, preViewId, rigid3d,“点”prePoints,...“特性”, preFeatures.Features);添加第二个关键帧currViewId = 2;vSetKeyFrames = addView(vSetKeyFrames, currViewId, relPose,“点”currPoints,...“特性”, currFeatures.Features);添加第一个和第二个关键帧之间的连接vSetKeyFrames = addConnection(vSetKeyFrames, preViewId, currViewId, relPose,“匹配”, indexPairs);添加3-D地图点[mappointment set, newPointIdx] = addWorldPoints(mappointment set, xyzWorldPoints);添加地图点的观测值preLocations = prePoints.Location;currLocations = currPoints.Location;presscales = prePoints.Scale;currScales = currPoints.Scale;在第一个关键帧中添加对应地图点的图像点mappointment set = addcorresponences (mappointment set, preViewId, newPointIdx, indexPairs(:,1));在第二个关键帧中添加对应地图点的图像点mappointment set = addcorresponences (mappointment set, currViewId, newPointIdx, indexPairs(:,2));

場所認識デ,タベ,スの初期化

ル,プ検出はbag -of-words,アプロ,チを使用して行われます。次の呼び出しを行うことにより,データセットに含まれる大量のイメージセットから抽出されたORB記述子を使用して,bagOfFeaturesオブジェクトで表されるビジュアルボキャブラリがオフラ@ @ンで作成されます。

bag = bagfeatures (imds,'CustomExtractor', @helperORBFeatureExtractorFunction, 'TreeProperties', [2,20], 'StrongestFeatures', 1);

ここで,洛桑国际管理发展学院は学習▪▪メ▪▪ジを格納するimageDatastoreオブジェクトであり,helperORBFeatureExtractorFunctionはorb特徴抽出器関数です。詳細にいては,袋装视觉文字を用いた画像検索を参照してください。

ルプクロジャ処理により,デタベスがンクリメンタルにビルドされます。このデ,タベ,スはinvertedImageIndexオブジェクトで表され,袋ORB功能によるビジュアルワードからイメージへのマッピングを格納します。

加载离线创建的特性数据包bofData = load(“bagOfFeaturesData.mat”);初始化位置识别数据库loopDatabase = invertedImageIndex(bofData.bof,“SaveFeatureLocations”、假);将前两个关键帧的特征添加到数据库中addmagefeatures (loopDatabase, preFeatures, preViewId);addmagefeatures (loopDatabase, currFeatures, currViewId);

初期再構成の調整と可視化

bundleAdjustmentを使用して,初期再構成を調整します。これにより,カメラ姿勢とワ,ルド座標点の両方を最適化し,全体の再投影誤差を最小化します。調整後,マップ点の3次元での位置,ビュ,の方向,深さの範囲などの属性が更新されます。helperVisualizeMotionAndStructureを使用して,マップ点とカメラの位置を可視化できます。

在前两个关键帧上运行完整的bundle调整跟踪= findTracks(vSetKeyFrames);cameraPoses = pose (vSetKeyFrames);[refinedPoints, refinedAbsPoses] = bundleadadjustment (xyzWorldPoints, tracks,...cameraPoses intrinsic,“FixedViewIDs”, 1...“PointsUndistorted”,真的,“AbsoluteTolerance”1 e -...“RelativeTolerance”1 e15汽油,“MaxIteration”, 20岁,...“规划求解”“preconditioned-conjugate-gradient”);使用地图点的中值深度缩放地图和相机姿势medianDepth = median(vecnorm(refinedPoints.'));refinedPoints = refine points / medianDepth;refinedAbsPoses.AbsolutePose (currViewId)。翻译=...refinedAbsPoses.AbsolutePose (currViewId)。翻译/ medianDepth;relPose。翻译= relPose.Translation/medianDepth;用精致的姿势更新关键帧vSetKeyFrames =升级视图(vSetKeyFrames, refinedAbsPoses);vSetKeyFrames = updateConnection(vSetKeyFrames, preViewId, currViewId, relPose);%更新地图点与细化的位置mapotset = updateWorldPoints(mapotset, newPointIdx, refinedPoints);更新视图方向和深度directionAndDepth = update(directionAndDepth, mappointment set, vSetKeyFrames。Views, newPointIdx, true);在当前帧中可视化匹配的特征关闭(hfeature.Parent.Parent);featurePlot = helperVisualizeMatchedFeatures(currI, currPoints(indexPairs(:,2)));

可视化初始地图点和相机轨迹mapPlot = helperVisualizeMotionAndStructure(vSetKeyFrames, mapotset);%显示图例showLegend (mapPlot);

トラッキング

トラッキング処理は全フレームを使用して行われ,新しいキーフレームを挿入するタイミングを決定します。この例を簡略化するため,ルプクロジャが見かったところでトラッキング処理を終了します。

当前关键帧的% ViewIdcurrKeyFrameId = currViewId;最后一个关键帧的% ViewIdlastKeyFrameId = currViewId;有最多共可见的参考关键帧的ViewId%映射点与当前关键帧refKeyFrameId = currViewId;输入图像序列中最后一个关键帧的索引lastKeyFrameIdx = currFrameIdx - 1;%输入图像序列中所有关键帧的索引addedFramesIdx = [1;lastKeyFrameIdx];isLoopClosed = false;

各フレ,ムが次のように処理されます。

  1. 新しいフレームごとにORB特徴が抽出され,既知の対応する3次元マップ点をもつ最後のキーフレームの特徴とのマッチングが行われます(matchFeaturesを使用)。

  2. estimateWorldCameraPoseを使用し,透視n点アルゴリズムでカメラ姿勢を推定します。

  3. matchFeaturesInRadiusを使用して,カメラ姿勢をもとに最後のキーフレームで観測されたマップ点を現在のフレームに投影し,特徴の対応関係を探索します。

  4. bundleAdjustmentMotionを使用して,現在のフレームにおける3次元から2次元への対応関係をもとに,動きのみのバンドル調整を行うことで,カメラ姿勢を調整します。

  5. matchFeaturesInRadiusを使用し,局所マップ点を現在のフレ,ムに投影して,その他の特徴の対応関係を探索します。そして,bundleAdjustmentMotionを使用して,再度カメラ姿勢を調整します。

  6. トラッキングの最後のステップでは,現在のフレ,ムが新しいキ,フレ,ムかどうかを決定します。現在のフレ,ムがキ,フレ,ムの場合,局所マッピング処理に進みます。そうでない場合,次のフレ,ムのトラッキングを開始します。

%主循环~isLoopClosed && currFrameIdx < numel(imds. files) currI = readimage(imds, currFrameIdx);[currFeatures, currPoints] = helperDetectAndExtractFeatures(currI, scaleFactor, numLevels, numPoints);跟踪最后一个关键帧% mappointment sidx:当前帧中观察到的映射点的索引% featureIdx:表中对应特征点的索引%电流帧[currPose, mappointment sidx, featureIdx] = helperTrackLastKeyFrame(mappointment set,...vSetKeyFrames。的观点,currFeatures, currPoints, lastKeyFrameId, intrinsics, scaleFactor);跟踪本地地图refKeyFrameId:包含最多的参考关键帧的ViewId%与当前帧共可见的地图点localKeyFrameIds:当前帧中连接的关键帧的ViewId[refKeyFrameId, localKeyFrameIds, currPose, mapPointsIdx, featureIdx] =...helptracklocalmap (mappointment set, directionAndDepth, vSetKeyFrames, mappointment sidx,...featureIdx, currPose, currFeatures, currPoints, intrinsic, scaleFactor, numLevels);检查当前帧是否是关键帧。如果满足以下两个条件,一个帧就是关键帧:% 1。自最后一个关键帧或%当前帧跟踪少于100个地图点% 2。当前帧跟踪的地图点小于90%由参考关键帧跟踪的%点numSkipFrames = 20;isKeyFrame = helperIsKeyFrame(mapotset, refKeyFrameId, lastKeyFrameIdx,...currFrameIdx, mappointment sidx, numSkipFrames);%可视化匹配的特征updatePlot(featurePlot, currI, currPoints(featureIdx));如果~isKeyFrame currFrameIdx = currFrameIdx + 1;继续结束更新当前关键帧IDcurrKeyFrameId = currKeyFrameId + 1

局所マッピング

局所マッピングはすべてのキ,フレ,ムに対して行われます。新しいキーフレームが決定されると,それをキーフレームに追加し,新しいキーフレームにおいて観測されたマップ点の属性を更新します。mapPointSetに含まれる外れ値をできるだけ少なくするには,有効なマップ点が少なくとも3つのキーフレームで観測されなければなりません。

現在のキーフレームにおけるORB特徴点と,接続されたキーフレームを三角形分割することで,新しいマップ点が作成されます。matchFeaturesを使用して,現在のキーフレームにおける不一致の特徴点ごとに,接続されたキーフレームにおいて,他の不一致の点との一致を探索します。局所バンドル調整により,現在のキーフレームの姿勢,接続されたキーフレームの姿勢,およびこれらのキーフレームで観測されたすべてのマップ点を調整します。

添加新的关键帧[mapetset, vSetKeyFrames] = helperAddNewKeyFrame(mapetset, vSetKeyFrames,...currPose, currFeatures, currPoints, mapPointsIdx, featureIdx, localKeyFrameIds);移除在少于3个关键帧内观察到的离群地图点[mappointment set, directionAndDepth, mappointment sidx] = helperCullRecentMapPoints(mappointment set, directionAndDepth, mappointment sidx)...directionAndDepth, mappointment sidx, newPointIdx);通过三角测量创建新的地图点minNumMatches = 20;minParallax = 3;[mapetset, vSetKeyFrames, newPointIdx] = helperCreateNewMapPoints(mapetset, vSetKeyFrames,...currKeyFrameId, intrinsic, scaleFactor, minNumMatches, minParallax);更新视图方向和深度directionAndDepth = update(directionAndDepth, mappointment set, vSetKeyFrames。的观点,...[mapPointsIdx;newPointIdx),真正的);%本地bundle调整[mapPointSet, directionAndDepth, vSetKeyFrames, newPointIdx] = helperLocalBundleAdjustment(...mappointment, directionAndDepth, vSetKeyFrames...currKeyFrameId, intrinsic, newPointIdx);可视化3D世界点和相机轨迹updatePlot(mapPlot, vSetKeyFrames, mapotset);

ル,プクロ,ジャ

ループクロージャの検出ステップでは,局所マッピング処理で処理された現在のキーフレームを受け取り,ループを検出して閉じようと試みます。evaluateImageRetrievalを使用し,データベース内のイメージをクエリすることで,現在のキーフレームと視覚的に似ているループ候補が特定されます。候補キーフレームが最後のキーフレームと接続されておらず,隣接するキーフレームの3つがループ候補であれば,その候補キーフレームは有効です。

有効なルプ候補が見かると,estimateGeometricTransform3Dを使用して,ル,プ候補フレ,ムと現在のキ,フレ,ムの間の相対姿勢を計算します。相対姿勢は,affine3dオブジェクトに保存されている3次元相似変換を表します。そして,ル,プの接続を相対姿勢と共に追加し,mapPointSetvSetKeyFramesを更新します。

在一些关键帧创建后检查循环是否关闭如果currKeyFrameId > 20循环边特征匹配的最小个数loopEdgeNumMatches = 50;检测可能的闭环关键帧候选[isDetected, validLoopCandidates] = helperCheckLoopClosure(vSetKeyFrames, currKeyFrameId,...loopDatabase, currI, loopEdgeNumMatches);如果isDetected添加循环关闭连接[isLoopClosed, mapPointSet, vSetKeyFrames] = helperAddLoopConnections(...mapPointSet, vSetKeyFrames, validloopcandidate, currKeyFrameId,...currFeatures, currPoints, loopEdgeNumMatches);结束结束%如果未检测到循环关闭,则将当前特性添加到数据库中如果~isLoopClosed addImageFeatures(loopDatabase, currFeatures, currKeyFrameId);结束更新id和索引lastKeyFrameId = currKeyFrameId;lastKeyFrameIdx = currFrameIdx;addedFramesIdx = [addedFramesIdx;currFrameIdx];% #好< AGROW >currFrameIdx = currFrameIdx + 1;结束主循环结束

循环边缘添加在关键帧:4和187之间

最後に,vSetKeyFramesの基本グラフ全体に対して相似姿勢グラフの最適化が行われ,カメラ姿勢のドリフトが修正されます。本质グラフは,可可视性グラフの接続のう,一致数がminNumMatchesよりも少ない接続を削除することで,内部的に作成されます。相似姿勢グラフの最適化後,最適化された姿勢と関連付けられたスケールを使用してマップ点の3次元での位置を更新します。

%优化姿势minNumMatches = 30;[vSetKeyFramesOptim, poseScales] = optimizepositions (vSetKeyFrames, minNumMatches,“宽容”1 e-16);优化姿势后更新地图点mappointment set = helperUpdateGlobalMap(mappointment set, directionAndDepth,...vSetKeyFrames, vSetKeyFramesOptim, poseScales;updatePlot(mapPlot, vSetKeyFrames, mapotset);绘制优化后的相机轨迹optimizedposed = pose (vSetKeyFramesOptim);plotOptimizedTrajectory (mapPlot optimizedPoses)%更新图例showLegend (mapPlot);

グラウンドトゥル,スとの比較

最適化されたカメラの軌跡をグラウンドトゥルースと比較して,ORB-SLAMの精度を評価できます。ダウンロ,ドしたデ,タには,各フレ,ムのカメラ姿勢のグラウンドトゥル,スが格納されたgroundtruth.txtファ@ @ルが含まれています。デタはmatファル形式で保存されています。軌跡の平方根平均二乗誤差(rmse)の推定を計算することもできます。

%负载地面真实值gTruthData = load(“orbslamGroundTruth.mat”);gTruth = gTruthData.gTruth;绘制实际相机轨迹plotActualTrajectory(mapPlot, gTruth(addedFramesIdx), optimizedpositions);%显示图例showLegend (mapPlot);

评估跟踪精度helperEstimateTrajectoryError (gTruth (addedFramesIdx) optimizedPoses);
关键帧轨迹的绝对RMSE (m): 0.054353

ORB-SLAMを使用して,屋内環境マップをビルドし,カメラの軌跡を推定する方法の概要は,以上になります。次のパラメーターを調整することにより,さまざまなデータセットで视觉大满贯パイプラインをテストできます。

  • numPoints:480 x 640ピクセルのaapl .メ.ジ解像度の場合,numPointsを1000に設定します。720 x 1280などの高解像度の場合は,2000に設定します。値が大きいほど,特徴抽出に時間がかかります。

  • numSkipFrames:フレ,ムレ,トが30 FPSの場合,numSkipFramesを20に設定します。フレ,ムレ,トが低い場合はより小さい値を設定します。numSkipFramesを増やすと追跡速度が向上しますが,カメラの動きが速い場合に追跡対象を見失うことがあります。

サポ,ト関数

短い補助関数は以下のとおりです。大きな関数は別ファ@ @ルにあります。

“helperAddLoopConnections”は,現在のキ,フレ,ムと有効なル,プ候補の間の接続を追加します。

“helperAddNewKeyFrame”は,キ,フレ,ムセットにキ,フレ,ムを追加します。

“helperCheckLoopClosure”は,視覚的に似たイメージをデータベースから取得することで,ループ候補となるキーフレームを検出します。

“helperCreateNewMapPoints”は,三角形分割により,新しいマップ点を作成します。

“helperLocalBundleAdjustment”は,現在のキ,フレ,ムの姿勢と周囲のシ,ンのマップを調整します。

“helperORBFeatureExtractorFunction”は,bagfeaturesで使用されるORB特徴抽出を実装します。

“helperTrackLastKeyFrame”は,最後のキ,フレ,ムのトラッキングにより,現在のカメラ姿勢を推定します。

“helperTrackLocalMap”は,局所マップのトラッキングにより,現在のカメラ姿勢を調整します。

“helperViewDirectionAndDepth”は,マップ点の平均的なビュ,の方向と予測される深度を保存します。

“helperVisualizeMatchedFeatures”は,フレ,ム内のマッチした特徴を表示します。

“helperVisualizeMotionAndStructure”は,マップ点とカメラの軌跡を表示します。

“helperDetectAndExtractFeatures”は,特徴を検出して抽出します。

函数[features, validPoints] = helperDetectAndExtractFeatures(Irgb,...scaleFactor, numLevels, numPoints, varargin)在本例中,图像已经是未扭曲的。总的来说%工作流,取消以下代码的注释以恢复图像的扭曲。% if nargin >% intrinsic = varargin{1};%结束% Irgb = undistortion timage (Irgb, intrinsic);检测ORB特征Igray = im2gray(Irgb);点= detectorb特征(灰色,“ScaleFactor”scaleFactor,“NumLevels”, numLevels);选择特征的子集,均匀分布在整个图像中points = selectUniform(points, numPoints, size(灰色,1:2));提取特征[features, validPoints] = extractFeatures(灰色,点);结束

“helperHomographyScore”は,ホモグラフィを計算し,再構成を評価します。

函数[H, score, inliersLogicalIndex] = helpcomputehomography (matchedPoints1, matchedPoints2) [H, inliersLogicalIndex] = estimateGeometricTransform2D(...matchedPoints1 matchedPoints2,“射影”...“MaxNumTrials”1 e3,“MaxDistance”4“信心”, 90);inliersLogicalIndex = matchedPoints1;inliersLogicalIndex = matchedPoints2;inliersLogicalIndex = find(inliersLogicalIndex);location1 = inlierPoints1.Location;locations2 = inlierPoints2.Location;xy1In2 = transformPointsForward(H, location1);xy2In1 = transformPointsInverse(H, locations2);error1in2 = sum((locations2 - xy1In2)。2) ^ 2;error2in1 = sum((location1 - xy2In1)。2) ^ 2; outlierThreshold = 6; score = sum(max(outlierThreshold-error1in2, 0)) +...sum (max (outlierThreshold-error2in1, 0));结束

“helperFundamentalMatrixScore”は,基礎行列を計算し,再構成を評価します。

函数[F, score, inliersIndex] = helperComputeFundamentalMatrix(matchedPoints1, matchedPoints2) [F, inliersLogicalIndex] = estimatfundamental matrix (...matchedPoints1 matchedPoints2,“方法”“RANSAC”...“NumTrials”1 e3,“DistanceThreshold”, 0.01);inliersLogicalIndex = matchedPoints1;inliersLogicalIndex = matchedPoints2;inliersLogicalIndex = find(inliersLogicalIndex);location1 = inlierPoints1.Location;locations2 = inlierPoints2.Location;%点到极线的距离lineIn1 = epipolarLine(F', locations2);Error2in1 = (sum([locations1, ones(size(locations1, 1),1)]。* lineIn1, 2)).^2...。/笔(lineIn1(:, 1:2)。2) ^ 2;lineIn2 = epipolarLine(F, location1);Error1in2 = (sum([locations2, ones(size(locations2, 1),1)]。* lineIn2, 2)).^2...。/笔(lineIn2(:, 1:2)。2) ^ 2;outlierThreshold = 4;score = sum(max(outlierThreshold-error1in2, 0)) +...sum (max (outlierThreshold-error2in1, 0));结束

“helperTriangulateTwoFrames”は,2 .。

函数[isValid, xyzPoints, inlierIdx] = helperTriangulateTwoFrames(...pose1, pose2, matchedPoints1, matchedPoints2, intrinsic, minParallax) [R1, t1] = cameraPoseToExtrinsics(pose1。旋转,pose1.Translation);camMatrix1 = cameraMatrix(intrinsic, R1, t1);[R2, t2] = cameraPoseToExtrinsics(pose2.)旋转,pose2.Translation);camMatrix2 = cameraMatrix(intrinsic, R2, t2);[xyzPoints, reprojectionErrors, isInFront] = triangulate(matchedPoints1,...matchedPoints2, camMatrix1, camMatrix2);通过视图方向和重投影误差筛选点minrerjerror = 1;inlierIdx = isInFront & reprojectionErrors < minrerjerror;xyzPoints = xyzPoints(inlierIdx,:);一个具有显著视差的良好的双视图。ray1 = xyzPoints - pose1.翻译;ray2 = xyzPoints - pose2.翻译;cosAngle = sum(ray1 .* ray2, 2) ./ (vecnorm(ray1, 2,2) .* vecnorm(ray2, 2,2));检查视差isValid = all(cosAngle < cosd(minParallax) & cosAngle>0);结束

“helperIsKeyFrame”は,フレ,ムがキ,フレ,ムかどうかをチェックします。

函数isKeyFrame = helperIsKeyFrame...refKeyFrameId, lastKeyFrameIndex, currFrameIndex, mapPointsIndices, numSkipFrames) numPointsRefKeyFrame = num (findWorldPointsInView(mapPoints, refKeyFrameId));从上次插入关键帧到现在已经超过20帧tooManyNonKeyFrames = currFrameIndex > lastKeyFrameIndex + numSkipFrames;追踪少于100个地图点tooFewMapPoints = numel(mappointment sindices) < 100;%被跟踪的地图点少于被跟踪点的90%%参考关键帧tooFewTrackedPoints = nummel (mapPointsIndices) < 0.9 * numPointsRefKeyFrame;isKeyFrame = (tooManyNonKeyFrames || tooFewMapPoints) && tooFewTrackedPoints;结束

“helperCullRecentMapPoints”は,最近追加されたマップ点をカリングします。

函数[mappointment set, directionAndDepth, mappointment sidx] = helperCullRecentMapPoints(mappointment set, directionAndDepth, mappointment sidx, newPointIdx) outlierIdx = setdiff(newPointIdx, mappointment sidx);如果~isempty(outlierIdx) mappointment set = removeWorldPoints(mappointment set, outlierIdx);directionAndDepth = remove(directionAndDepth, outlierIdx);mappointment sidx = mappointment sidx - arrayfun(@(x) nnz(x>outlierIdx), mappointment sidx);结束结束

“helperEstimateTrajectoryError”は,追跡エラ,を計算します。

函数rmse = helperEstimateTrajectoryError(gTruth, cameraPoses) locations = vertcat(cameraPoses. absolutepose . translation);gLocations = vertcat(gTruth.Translation);scale = median(vecnorm(gLocations, 2,2))/ median(vecnorm(locations, 2,2));scaledLocations =位置*规模;rmse = sqrt(mean(sum((scaledLocations - gLocations)。^2, 2)));disp ([关键帧轨迹的绝对RMSE (m):num2str (rmse)]);结束

“helperUpdateGlobalMap”は,姿勢グラフの最適化後にマップ点の3次元位置を更新します。

函数[mapPointSet, directionAndDepth] = helperUpdateGlobalMap(...mapPointSet, directionAndDepth, vSetKeyFrames, vSetKeyFramesOptim, poseScales)%helperUpdateGlobalMap在姿态图优化后更新地图点posesOld = vSetKeyFrames.Views.AbsolutePose;posesNew = vSetKeyFramesOptim.Views.AbsolutePose;positionsOld = mappointment . worldpoints;positionsNew = positionsOld;指数= 1:mappointment . count;根据的新绝对姿态更新每个地图点的世界位置%对应的主要视图i = indexes majorViewIds = directionAndDepth.MajorViewId(i);posennew = posesNew(majorViewIds).T;poseNew(1:3, 1:3) = poseNew(1:3, 1:3) * poseScales(majorViewIds);tform = posesOld(majorViewIds)。T \ posennew;positionsOld(i,:) * tform(1:3,1:3) + tform(4,1:3);结束mappointment set = updateWorldPoints(mappointment set, indexes, posisnew);结束

参考文献

穆尔-阿塔尔,劳尔,何塞·玛丽亚·马丁内斯·蒙蒂埃尔,胡安·d·塔尔多斯。“ORB-SLAM:一种多功能和精确的单目SLAM系统。”IEEE机器人汇刊31日。5, pp 1147-116, 2015。

[2] Sturm, Jürgen, Nikolas Engelhard, Felix Endres, Wolfram Burgard和Daniel Cremers。“RGB-D SLAM系统评估基准”。在IEEE/RSJ智能机器人与系统国际会议论文集, pp. 573-580, 2012。

関連するトピック