主要内容

从多个视图运动生成结构

运动结构(SfM)是从一组二维视图估计场景的三维结构的过程。它被用于许多应用,如机器人导航、自动驾驶和增强现实。此示例演示如何从一系列视图估计校准摄影机的姿势,并将场景的三维结构重建到未知比例因子。

概述

此示例显示了如何从使用使用相机校准的摄像机拍摄的二维视图序列中重建三维场景相机校准器. 该示例使用imageviewset对象来存储和管理与每个视图相关联的数据,例如摄影机姿势和图像点,以及来自成对视图的点之间的匹配。

该示例使用成对点匹配来估计当前视图相对于前一个视图的摄像机姿态。然后,它将成对匹配链接到跨越多个视图的更长的点跟踪findTracks方法imageviewset对象。这些轨道然后作为输入多视图三角测量使用triangulateMultiview函数,以及相机姿态和三维场景点的细化捆绑式调整函数。

该实例包括两个主要部分:摄像机运动估计和密集场景重建。在第一部分中,示例使用一个稀疏的点集来估计每个视图的相机姿态。在第二部分中,示例再次遍历视图序列,使用Vision.PointCracker.跟踪视图中密集的点集,计算场景的密集三维重建。

摄像机运动估计算法由以下步骤组成:

  1. 对于每对连续图像,查找一组点对应关系。此示例使用使用的兴趣点探测拍摄函数,使用该功能提取特征描述符提取特征函数,并使用匹配特征函数。或者,您可以使用Vision.PointCracker.

  2. 估计当前视图的相对姿态,这是摄像机相对于前一个视图的方向和位置。这个例子使用了一个辅助函数helperEstimateRelativePose,其中估计基本矩阵relativecamerapose.

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

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

  5. 将Inlier匹配存储在上一个和当前视图之间。

  6. 在迄今为止处理的所有视图中查找点轨迹。

  7. 使用triangulateMultiview函数来计算轨道对应的初始三维位置。

  8. 使用捆绑式调整功能来改进相机的姿态和三维点。将精致的相机姿势储存在imageviewset对象。

读取输入图像序列

读取并显示图像序列。

%使用| imageDatastore |获取一个数据库中所有图像文件名的列表%目录。imageDir=完整文件(toolboxdir(“愿景”),“visiondata”...“structureFromMotion”); imds=图像数据存储(imageDir);%显示图像。图蒙太奇(imds.Files,“尺寸”,[3,2]);%将图像转换为灰度。图像=单元格(1,Numel(IMDS.Files));对于i = 1:numel(imds. files) i = readimage(imds, i);{我}= im2gray图像(i);结束头衔(输入图像序列的);

图中包含一个坐标轴。标题为Input Image Sequence的轴包含一个Image类型的对象。

加载摄像机参数

加载cameraParameters使用相机校准器

data =加载(fullfile (imageDir“cameraParams.mat”));cameraParams = data.cameraParams;

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

使用一个imageviewset对象来存储和管理与每个视图关联的图像点和相机姿势,以及视图对之间的点匹配。一旦您填充了imageviewset对象,你可以使用它在多个视图中找到点轨迹和检索相机的姿态要使用triangulateMultiview捆绑式调整职能。

%获得相机的内在参数intrinsics=cameraParams.intrinsics;不失真的第一个图像。I=未失真图像(图像{1},本质);%检测功能。增加“NumOctaves”有助于检测大规模%高分辨率图像中的功能。使用ROI消除虚假信息%特征围绕图像的边缘。边境= 50;roi = [border, border, size(I, 2)- 2*border, size(I, 1)- 2*border];prevPoints = detectSURFFeatures(我'numoctaves',8,“投资回报率”,ROI);%提取特征。只要使用“直立”功能可以提高匹配相机的运动很少或没有涉及到面内旋转。prevFeatures=提取特征(I,prevPoints,“正直”,真正的);%创建一个空的imageviewset对象来管理与每个对象关联的数据%视图。vSet = imageviewset;%添加第一个视图。放置与第一个视图关联的相机%以及沿Z轴定向的原点。viewId = 1;vSet = addView(vSet, viewId, rigid3d,“点”, prevPoints);

添加其余的视图

通过其余的图像。对于每个镜头

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

  2. 估计当前视图相对于前一个视图的摄像机姿态。

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

  4. 对初始三维世界点进行三角剖分。

  5. 使用束调整优化所有摄影机姿势和三维世界点。

对于i = 2:numel(图像)%undistort当前图像。I = undistortion timage (images{I}, intrinsics);%检测、提取和匹配特征。currPoints=检测到的特征(I,'numoctaves',8,“投资回报率”,投资回报率);currFeatures=提取特征(I,currPoints,“正直”,真正的);indexPairs = matchFeatures(prevFeatures, currFeatures,...“最大比率”,.7,“独一无二”,真正的);%选择匹配点。matchedpoints1 = prevpoints(IndexPairs(:,1));matchedpoints2 = CurrPoints(IndexPairs(:,2));%估计当前视图相对于前一视图的摄影机姿势。姿势是按比例计算的,这意味着两者之间的距离上一个视图中的摄像机和当前视图设置为1。%这将通过捆束调整进行纠正。[relativeOrient, relativeLoc, inlierIdx] = helperEstimateRelativePose(...matchedpoints1,matchedpoints2,内在的);%获取包含上一个摄影机姿势的表。普遍=姿势(vset,i-1).absolutepose;有关= rigid3d(相对符,relativeloc);%计算全局坐标系中的当前相机姿势%相对于第一个视图。施加= rigid3d(resimed.t * precul.t);%将当前视图添加到视图集中。vSet=添加视图(vSet,i,currPose,“点”, currPoints);%存储上一个视图和当前视图之间的点匹配。vSet = addConnection(vSet, i-1, i, relPose,“火柴”indexPairs (inlierIdx:));%查找所有视图中的点轨迹。轨道=findTracks(vSet);%获取包含所有视图的相机姿势的表格。camPoses=姿势(vSet);三角定位三维世界点的初始位置。XYZPOINTS = TRINGULATEMULTIEWIEW(轨道,野营,内在);%优化三维世界点和摄影机姿势。[xyzPoints, campose, reprojectionErrors] = bundleAdjustment(xyzPoints,...曲目,野营,内在学,“FixedViewId”, 1...“PointsUndistorted”,真正的);存储精致的相机姿势。vSet=更新视图(vSet,camPoses);prevFeatures=currFeatures;prevPoints=currPoints;结束

显示相机的姿势

展示精致的相机姿势和三维世界点。

%显示相机姿势。camPoses=姿势(vSet);图形绘图仪(camPoses,“尺寸”, 0.2);持有%排除嘈杂的三维点。goodIdx=(重射者<5);XYZPOINTS = XYZPOINTS(GOODIDX,:);%显示3-D点。pcshow (xyzPoints'verticalaxis'“是的”“垂直方向”'下'...'Markersize', 45); 网格持有%指定查看音量。loc1=钟形。绝对姿势(1)。翻译;xlim([loc1(1)-5,loc1(1)+4]);ylim([loc1(2)-5,loc1(2)+4]);zlim([loc1(3)-1,loc1(3)+20]);camorbit(0,-30);头衔(“精致的相机姿势”);

图中包含一个坐标轴。带有标题精制摄像头的轴姿势包含51个类型的类型,文本,补丁,分散。

计算密集重建

再看一遍图片。这一次检测一组密集的角点,并使用Vision.PointCracker.

读取并校正第一个图像I=未失真图像(图像{1},本质);%检测第一个图像中的角。prevPoints=detectMinEigenFeatures(I,“肉质”,0.001);创建点跟踪器对象来跨视图跟踪点。Tracker = Vision.PointCracker('maxbidirectionalerror', 1“Numpyramidalevels”6);初始化点跟踪器。prevPoints = prevPoints.Location;初始化(prevPoints追踪,我);%将密集点存储在视图集中。vSet=更新连接(vSet,1,2,“火柴”, 0 (0, 2));vSet = updateView(vSet, 1,)“点”, prevPoints);%在所有视图中跟踪点。对于i = 2:numel(图像)%读取并取消对当前图像的扭曲。I = undistortion timage (images{I}, intrinsics);%追踪要点。[currPoints, valididdx] = step(tracker, I);%清除点之间的旧匹配。如果“火柴”, 0 (0, 2));结束vSet=updateView(vSet,i,“点”, currPoints);%存储视图集中的点匹配。matches=repmat((1:size(prevPoints,1)),[1,2]);匹配项=匹配项(validix,:);vSet=更新连接(vSet,i-1,i,“火柴”, 火柴);结束%查找所有视图中的点轨迹。轨道=findTracks(vSet);%查找所有视图中的点轨迹。camPoses=姿势(vSet);三角定位三维世界点的初始位置。XYZPOINTS = TRINGULATEMULTIEWIEW(轨道,野营,...内在杂志);%优化三维世界点和摄影机姿势。[xyzPoints、campos、reprojectioner]=捆绑调整(...XYZPOINTS,轨道,野营,内在学,“FixedViewId”, 1...“PointsUndistorted”,真正的);

显示密集重建

显示摄影机姿势和密集点云。

%显示精制的相机姿势。图形绘图仪(camPoses,“尺寸”, 0.2);持有%排除嘈杂的三维世界点。goodIdx=(重射者<5);%显示密集的3-D世界点。pcshow(xyzpoints(goodidx,:),'verticalaxis'“是的”“垂直方向”'下'...'Markersize', 45); 网格持有%指定查看音量。loc1=钟形。绝对姿势(1)。翻译;xlim([loc1(1)-5,loc1(1)+4]);ylim([loc1(2)-5,loc1(2)+4]);zlim([loc1(3)-1,loc1(3)+20]);camorbit(0,-30);头衔('密集重建');

图中包含一个坐标轴。带有标题密集重建的轴包含51个类型的类型线,文本,补丁,分散。

参考

[1] m.i.a.卢克西斯和A.A.argyros(2009)。“SBA:用于通用稀疏捆绑调整的软件包”。数学软件(ACM)36(1):1-30的ACM交易。

[2] R。哈特利,A。Zisserman,“计算机视觉中的多视图几何”,剑桥大学出版社,2003年。

[3] b区格;p . McLauchlan;r·哈特利;菲茨吉本(1999)。《Bundle Adjustment: A Modern Synthesis》。国际视觉算法研讨会论文集。斯普林格出版社。298 - 372页。