主要内容

从多个视图运动生成结构

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

概述

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

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

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

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

  1. 对于每一对连续的图像,找到一组对应的点。方法检测兴趣点detectSURFFeatures函数提取特征描述符提取特征函数,并使用匹配特征函数。或者,您可以使用愿景。PointTracker

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

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

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

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

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

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

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

读取输入图像序列

读取并显示图像序列。

%使用| imageDatastore |获取一个数据库中所有图像文件名的列表%目录。imageDir=完整文件(toolboxdir(“愿景”),“visiondata”...“structureFromMotion”);imds=图像数据存储(imageDir);%显示图像。图蒙太奇(imds.Files,“尺寸”, 3, 2);%将图像转换为灰度。images = cell(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. 使用束调整优化所有摄影机姿势和三维世界点。

对于我= 2:元素个数(图片)%恢复当前图像的失真。I = undistortion timage (images{I}, intrinsics);%检测、提取和匹配特征。currPoints=检测到的特征(I,“NumOctaves”8“投资回报率”,roi);currFeatures=extractFeatures(I,currPoints,“正直”,真正的);indexPairs = matchFeatures(prevFeatures, currFeatures,...“最大比率”7,“独一无二”,真正的);%选择匹配点。matchedpoint1 = prevPoints(indexPairs(:, 1));matchedpoint2 = currPoints(indexPairs(:, 2));%估计当前视图相对于前一视图的摄影机姿势。姿势是按比例计算的,这意味着两者之间的距离%前一个视图和当前视图的摄像机设置为1。%这将通过捆束调整进行纠正。[relativeOrient, relativeLoc, inlierIdx] = helperEstimateRelativePose(...matchedPoints1、matchedPoints2 intrinsic);%获取包含上一个摄影机姿势的表。prevPose = pose (vSet, i-1).AbsolutePose;relPose = rigid3d(relativeOrient, relativeLoc);在全局坐标系中计算当前摄像机的姿态%相对于第一个视图。currPose = rigid3d (relPose。T * prevPose.T);%将当前视图添加到视图集中。vSet=添加视图(vSet,i,currPose,“点”, currPoints);%存储上一个视图和当前视图之间的点匹配。vSet = addConnection(vSet, i-1, i, relPose,“火柴”indexPairs (inlierIdx:));在所有视图中找到点轨迹。轨道=findTracks(vSet);%获取包含所有视图的相机姿势的表格。camPoses=姿势(vSet);三角定位三维世界点的初始位置。xyzPoints = triangulateMultiview(tracks, campose, intrinsics);%优化三维世界点和摄影机姿势。[xyzPoints, campose, reprojectionErrors] = bundleAdjustment(xyzPoints,...intrinsic痕迹,坎波斯,“FixedViewId”, 1...“PointsUndistorted”,真正的);存储精致的相机姿势。vSet=updateView(vSet,camPoses);prevFeatures=currFeatures;prevPoints=currPoints;结束

显示相机的姿势

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

%显示相机姿势。camPoses=姿势(vSet);图形;绘图摄影机(camPoses,“尺寸”, 0.2);持有%排除嘈杂的三维点。goodIdx = (reprojectionErrors < 5);xyzPoints = xyzPoints(goodIdx,:);%显示3d点。pcshow (xyzPoints“VerticalAxis”“是的”“垂直方向”“下来”...“MarkerSize”,45);网格持有%指定查看音量。loc1=camPoses.绝对姿势(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个类型为线、文本、补丁、散点的对象。

计算密集重建

再次浏览图像。这次检测一组密集的角点,并使用愿景。PointTracker

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

显示密度重建

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

显示精致的相机姿势。图:绘图仪(camPoses、,“尺寸”, 0.2);持有%排除嘈杂的三维世界点。goodIdx = (reprojectionErrors < 5);%显示密集的三维世界点。pcshow (xyzPoints (goodIdx:)“VerticalAxis”“是的”“垂直方向”“下来”...“MarkerSize”,45);网格持有%指定查看音量。loc1=camPoses.绝对姿势(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个类型为line, text, patch, scatter的对象。

参考文献

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

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

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