主要内容

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

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

概述

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

该示例使用成对点匹配来估计当前视图的相机姿势相对于上一个视图。然后,它将成对匹配链接到跨越多个视图的更长点轨道使用findtracks.方法的方法imageviewset.目的。然后,这些轨道用作使用该曲线的输入到多视图三角测量triangulatemultiewiew.相机姿势的功能和改进和使用的3-D场景点Bundleadjustment.功能。

该示例由两个主要部分组成:相机运动估计和密集场景重建。在第一部分中,该示例估计使用跨视图匹配的稀疏点集的每个视图的相机姿势。在第二部分中,示例再次迭代视图序列,使用愿景。PointTracker要追踪视图中的密集点,以计算场景的密集三维重建。

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

  1. 对于每一对连续的图像,找到一组点对应。控件检测兴趣点detectSURFFeatures方法提取特性描述符提取物质函数,并使用该函数找到匹配项matchfeatures.功能。或者,您可以使用视图追踪点愿景。PointTracker

  2. 估计当前视图的相对姿势,其是相对于前一个视图的相机方向和位置。该示例使用辅助功能HelperestimaterElativepose,呼叫EstIsionesentialMatrix.relativeCameraPose

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

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

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

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

  7. 使用triangulatemultiewiew.函数来计算与轨道对应的初始3-D位置。

  8. 使用Bundleadjustment.功能要改进相机姿势和3-D点。将精致的相机置于姿势imageviewset.目的。

读取输入图像序列

读取并显示图像序列。

%使用| ImageageAtastore |获取a中的所有图像文件名的列表% 目录。imagedir = fullfile(toolboxdir('想象'),'VisionData'......'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);结尾标题('输入图像序列');

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

加载相机参数

加载Cameraparameters.使用的对象相机校准器

data = load(fullfile(imagedir,'cameraparams.mat'));cameraparams = data.cameraparams;

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

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

%获取相机的内在参数内在= cameraparams.intrinsics;%贴不变第一图像。i = untostortimage(图像{1},内在ici);%检测功能。增加'numoctaves'有助于检测大规模高分辨率图像中的%功能。使用ROI消除杂散图像边缘周围的%特征。边界= 50;ROI = [边框,边框,大小(I,2) -  2 *边框,尺寸(I,1) -  2 *边框];prevpoints = detectsurfepures(我,“NumOctaves”8'roi',ROI);%提取特征。使用“直立”功能可以改善匹配,只要%相机运动涉及较少或没有面内旋转。prevfeatures =提取物(i,prevpoints,'直立', 真的);%创建一个空映像viewset对象,以管理与每个关联的数据% 看法。vset = imageviewset;%添加第一个视图。将相机与第一个视图相关联%和沿z轴定向的原点。viewid = 1;vset = addview(Vset,ViewID,Rigid3D,“点”,prevpoints);

添加其余的视图

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

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

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

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

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

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

为了我= 2:元素个数(图片)%恢复当前图像的扭曲。i = untostortimage(图像{i},内在的);%检测,提取和匹配功能。CurrPoints = DetectSurfepures(我,“NumOctaves”8'roi',ROI);Currfeatures =提取物(I,Curpoints),'直立', 真的);IndexPairs = MatchFeatures(PrevFeatures,Currfeatures,......'maxratio'7,'独特', 真的);%选择匹配点。matchedPoints1 = prevPoints(indexPairs(:, 1));matchedPoints2 = currPoints(indexPairs(:, 2));%估计相对于上一个视图的当前视图的相机姿势。%姿势被计算为比例,这意味着之间的距离%前一个视图中的摄像头,当前视图设置为1。%这将通过捆绑调整来校正。[相对,relativeloc,Inlieridx] = HelperestimaterElativePosse(......matchedPoints1、matchedPoints2 intrinsic);%获取包含上一个相机姿势的表。prevPose =姿态(vSet, i-1).AbsolutePose;relPose = rigid3d(relativeOrient, relativeLoc);%在全局坐标系中计算当前摄像机姿态%相对于第一个视图。currPose = rigid3d (relPose。T * prevPose.T);%将当前视图添加到视图集。vset = addview(vset,i,urpery,“点”,curports);%存储上一个和当前视图之间的点匹配。vset = addConnection(vset,i-1,我,有影响,'火柴',indexpairs(Inlieridx,:));%查找所有视图的点轨迹。曲目= findtracks(vset);%获取包含相机姿势的表格所有视图。坎波斯=姿势(vset);%三角形初始位置为3-D世界点。xyzPoints = triangulateMultiview(tracks, campose, intrinsics);%优化3-D世界点和相机姿势。[XYZPOINTS,野营,repoumentErrors] = BundleAdjustment(XYZPoints,......intrinsic痕迹,坎波斯,'filedviewid',1,......'obessundistorted', 真的);%存储精制的相机姿势。vset = updateView(vset,野营);PrevFeatures = Currfeatures;prevpoints = curptpoints;结尾

显示相机姿势

显示精制的相机姿势和3-D世界点。

%显示相机姿势。坎波斯=姿势(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,“点”,prevpoints);%跟踪所有视图的点。为了我= 2:元素个数(图片)%读取并贴变当前图像。i = untostortimage(图像{i},内在的);%跟踪点。[FracPoints,Valididx] =步骤(跟踪器,i);%清除点之间的旧匹配。如果i < numel(images) vSet = updateConnection(vSet, i, i+1,'火柴',零(0,2));结尾vset = updateView(vset,i,“点”,curports);%在视图集中存储匹配点。matches = repmat((1:size(prevpoints,1))',[1,2]);matches = matches(valididx,:);vset = UpdateConnection(vset,i-1,我,'火柴',匹配);结尾%查找所有视图的点轨迹。曲目= findtracks(vset);%查找所有视图的点轨迹。坎波斯=姿势(vset);%三角形初始位置为3-D世界点。xyzPoints = triangulateMultiview(tracks, campose,......intrinsic);%优化3-D世界点和相机姿势。[XYZPOINTS,野营,重新评论错误] = BundleAdjustment(......xyzPoints, tracks, campose, intrinsics,'filedviewid',1,......'obessundistorted', 真的);

显示密度重建

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

%显示精致的相机姿势。数字;Plotcamera(野营,'尺寸',0.2);抓住%排除嘈杂的3-D世界点。goodIdx = (reprojectionErrors < 5);%显示密集的3d世界点。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);标题(“密集的重建”);

图中包含一个轴。标题为密集重建的坐标轴包含51个对象,分别是线、文本、补丁、散点。

参考文献

[1] M.I.A. Lourakis和A.A. Argyros(2009)。SBA:通用稀疏束调整的软件包。计算机数学学报(英文版)36(1):1-30。

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

[3] B. Triggs;P. Mclauchlan;R. Hartley;A. FitzGibbon(1999)。“捆绑调整:现代合成”。视觉算法国际研讨会的诉讼程序。Springer-Verlag。第298-372页。