主要内容

来自多种视图的运动的结构

来自运动的结构(SFM)是从一组二维视图估计场景的三维结构的过程。它用于许多应用程序,例如机器人导航,自主驾驶和增强现实。此示例显示了如何从一系列视图中估计校准相机的姿势,并将场景的三维结构重建为未知的比例因子。

概述

这个例子展示了如何从一个2d视图序列重建一个3d场景,使用校准的相机摄像机校准器.该示例使用图像视图集对象存储和管理与每个视图相关联的数据,例如摄像机姿势和图像点,以及从对视图的点之间的匹配。

该示例使用成对点匹配来估计当前视图相对于前一视图的摄影机姿势。然后,它使用findTracks方法的方法图像视图集这些轨迹然后用作使用三角多视图功能以及使用Bundleadjustment.功能。

该示例包括两个主要部分:摄影机运动估计和密集场景重建。在第一部分中,该示例使用在视图中匹配的稀疏点集估计每个视图的摄影机姿势。在第二部分中,该示例使用愿景。PointTracker要追踪视图中的密集点,以计算场景的密集三维重建。

摄像机运动估计算法包括以下步骤:

  1. 对于每一对连续的图像,找到一组对应的点。方法检测兴趣点detectSURFFeatures函数提取特征描述符提取物质函数,并使用该函数找到匹配项matchfeatures.作用或者,您可以使用以下命令跨视图跟踪点:愿景。PointTracker.

  2. 估计当前视图的相对姿态,即相对于上一视图的摄影机方向和位置。该示例使用了一个helper函数帮助估计相对姿势,呼叫EstIsionesentialMatrix.relativeCameraPose.

  3. 将当前视图的相对姿势转换为序列的第一视图的坐标系。

  4. 存储当前视图属性:相机姿势和图像点。

  5. 存储前一个视图和当前视图之间的inlier匹配。

  6. 在到目前为止处理的所有视图中查找点轨迹。

  7. 使用三角多视图函数计算与轨迹对应的初始三维位置。

  8. 使用Bundleadjustment.用于优化摄影机姿势和三维点的函数。将精致的相机姿势存储在图像视图集对象。

读取输入图像序列

读取并显示图像序列。

%使用| ImageageAtastore |获取a中的所有图像文件名的列表%目录。imageDir = fullfile (toolboxdir (“愿景”),“视觉数据”,...'structionfromotion');IMDS = IMAGEDATASTORE(IMAGEDIR);%显示图像。图蒙太奇(IMDS.Files,'尺寸', 3, 2);%将图像转换为灰度。images = cell(1, numel(imds.Files));为了i=1:numel(imds.Files)i=readimage(imds,i);图像{i}=im2gray(i);结尾标题(“输入图像序列”);

图中包含一个轴对象。具有标题输入映像序列的轴对象包含类型图像的对象。

加载相机参数

加载摄像机参数使用的对象摄像机校准器.

数据=加载(完整文件(imageDir,“cameraParams.mat”)); cameraParams=data.cameraParams;

创建包含第一个视图的视图集

使用图像视图集对象存储和管理与每个视图关联的图像点和相机姿势,以及对视图对之间的点匹配。一旦你填充了一个图像视图集对象,您可以使用它在多个视图中查找点轨迹,并检索要使用的摄影机姿势三角多视图Bundleadjustment.功能。

%获取相机的内在参数内在= cameraparams.intrinsics;%取消对第一个图像的扭曲。i = untostortimage(图像{1},内在ici);%检测功能。增加“NumOctaves”有助于检测大规模高分辨率图像中的%功能。使用ROI消除杂散%图像边缘周围的特征。border=50;roi=[边框,边框,大小(I,2)-2*边框,大小(I,1)-2*边框];prevPoints=detectSURFFeatures(I,“NumOctaves”8'roi',ROI);%提取特征。使用“直立”功能可以提高匹配,只要%相机运动几乎不涉及面内旋转。prevfeatures =提取物(i,prevpoints,“直立的”,对);%创建一个空的imageviewset对象以管理与每个对象关联的数据% 看法。vSet=图像视图集;%添加第一个视图。将相机与第一个视图相关联%和沿z轴定向的原点。viewId=1;vSet=添加视图(vSet、viewId、rigid3d、,“点”,分数);

添加其余视图

再看一遍剩下的图片。为每一个图像

  1. 上一个图像和当前图像之间的匹配点。

  2. 估计当前视图相对于前一视图的摄影机姿势。

  3. 计算当前视图在全局坐标系中相对于第一个视图的摄影机姿势。

  4. 三角形初始3-D世界点。

  5. 使用捆绑调整来改进所有相机姿势和3-D世界点。

为了我= 2:元素个数(图片)%恢复当前图像的失真。I=未失真图像(图像{I},本质);%检测,提取和匹配功能。CurrPoints = DetectSurfepures(我,“NumOctaves”8'roi',ROI);Currfeatures =提取物(I,Curpoints),“直立的”,true);indexPairs=匹配特征(prevFeatures、currFeatures、,...'maxratio'7,'独特的',对);%选择匹配点。matchedpoint1 = prevPoints(indexPairs(:, 1));matchedpoint2 = currPoints(indexPairs(:, 2));%估计相对于上一个视图的当前视图的相机姿势。%姿势是按比例计算的,这意味着%前一个视图和当前视图的摄像机设置为1。%这将通过捆绑调整来校正。[relativeOrient、relativeLoc、inlierIdx]=帮助估计相对姿态(...matchedPoints1、matchedPoints2 intrinsic);%获取包含上一个相机姿势的表。prevPose = pose (vSet, i-1).AbsolutePose;relPose = rigid3d(relativeOrient, relativeLoc);在全局坐标系中计算当前摄像机的姿态%相对于第一个视图。currPose = rigid3d (relPose。T * prevPose.T);%将当前视图添加到视图集。vset = addview(vset,i,urpery,“点”,货币点数);%存储上一个和当前视图之间的点匹配。vSet=添加连接(vSet,i-1,i,relPose,“匹配”,indexPairs(inlierIdx,:);在所有视图中找到点轨迹。曲目= findtracks(vset);%获取包含所有视图的摄影机姿势的表。坎波斯=姿势(vset);%对三维世界点的初始位置进行三角测量。xyzPoints = triangulateMultiview(tracks, campose, intrinsics);%优化3-D世界点和相机姿势。[xyzPoints,campos,reprojectioners]=捆绑调整(xyzPoints,...intrinsic痕迹,坎波斯,'filedviewid'1....“PointsUnderated”,对);%储存精致的相机姿势。vset = updateView(vset,野营);PrevFeatures = Currfeatures;prevpoints = curptpoints;结尾

显示相机姿势

显示优化的摄影机姿势和三维世界点。

%显示相机姿势。坎波斯=姿势(vset);数字;Plotcamera(野营,'尺寸', 0.2); 持有%排除嘈杂的3-D点。goodIdx = (reprojectionErrors < 5);xyzPoints = xyzPoints(goodIdx,:);%显示3d点。pcshow(xyzPoints,“VerticalAxis”,'是','verticalaxisdir',“下来”,...“MarkerSize”,45);网格持有%指定查看卷。Loc1 = Camposs.Absolutepose(1)。翻译;XLIM([LOC1(1)-5,LOC1(1)+4]);ylim([LOC1(2)-5,LOM1(2)+4]);ZLIM([LOC1(3)-1,LOM1(3)+20]);Camorbit(0,-30);标题('精制相机姿势');

图中包含一个轴对象。标题为“精致相机姿态”的轴对象包含51个类型为线、文本、补丁、散点的对象。

计算密集重建

再次通过图像。这次检测一个密集的角落,并在所有视图中跟踪它们愿景。PointTracker.

%读取并取消对第一个图像的扭曲i = untostortimage(图像{1},内在ici);%检测第一幅图像中的角点。prevpoints =侦听(I,'清点', 0.001);%创建点跟踪器对象以跨视图跟踪点。追踪=愿景。PointTracker (“MaxBidirectionalError”1.'numpyramidlevels'6);%初始化点跟踪器。prevPoints=prevPoints.Location;初始化(跟踪器,prevPoints,I);%存储视图集中的密集点。vset = UpdateConnection(vset,1,2,“匹配”,零(0,2));vSet=updateView(vSet,1,“点”,分数);%跟踪所有视图中的点。为了我= 2:元素个数(图片)%读取并贴变当前图像。I=未失真图像(图像{I},本质);%追踪积分。[currPoints,validix]=步进(跟踪器,I);%清除点之间的旧匹配。如果i < numel(images) vSet = updateConnection(vSet, i, i+1,)“匹配”,零(0,2));结尾vSet = updateView(vSet, i,“点”,货币点数);%在视图集中存储点匹配。matches = repmat((1:size(prevpoints,1))',[1,2]);matches = matches(valididx,:);vset = UpdateConnection(vset,i-1,i,“匹配”,匹配);结尾在所有视图中找到点轨迹。曲目= findtracks(vset);在所有视图中找到点轨迹。坎波斯=姿势(vset);%对三维世界点的初始位置进行三角测量。xyzPoints = triangulateMultiview(轨道,campose,...intrinsic);%优化3-D世界点和相机姿势。[XYZPOINTS,野营,重新评论错误] = BundleAdjustment(...xyzPoints, tracks, campose, intrinsics,'filedviewid'1....“PointsUnderated”,对);

显示密度重建

显示相机姿势和密集点云。

显示精致的相机姿势。数字;Plotcamera(野营,'尺寸', 0.2); 持有%排除嘈杂的3-D世界点。goodIdx = (reprojectionErrors < 5);%显示密集的三维世界点。pcshow (xyzPoints (goodIdx:)“VerticalAxis”,'是','verticalaxisdir',“下来”,...“MarkerSize”,45);网格持有%指定查看卷。Loc1 = Camposs.Absolutepose(1)。翻译;XLIM([LOC1(1)-5,LOC1(1)+4]);ylim([LOC1(2)-5,LOM1(2)+4]);ZLIM([LOC1(3)-1,LOM1(3)+20]);Camorbit(0,-30);标题(“密集的重建”);

图中包含一个Axis对象。标题为稠密重建的Axis对象包含51个类型为line、text、patch和District的对象。

参考文献

M.I.A. Lourakis和A.A. Argyros(2009)。SBA:通用稀疏束调整软件包。数学软件学报36(1):1-30。

[2] R. Hartley,A. Zisserman,“计算机愿景中的多视图几何”,2003年剑桥大学出版社。

[3] B.Triggs;麦克劳克兰;哈特利;A.Fitzgibbon(1999年)。“束调整:现代综合”。视觉算法国际研讨会论文集。斯普林格·维拉格。第298-372页。