结构从运动从多个视图
基于运动的结构(SfM)是从一组二维视图中估计场景的三维结构的过程。它被用于许多应用,如机器人导航、自动驾驶和增强现实。这个例子向您展示了如何从一系列视图中估计校准相机的姿势,并重建场景的三维结构,直至未知的比例因子。
概述
这个例子展示了如何从一系列的2-D视图中重建一个3-D场景相机校准器.该示例使用imageviewset
对象来存储和管理与每个视图相关的数据,例如相机姿势和图像点,以及视图对中点之间的匹配。
该示例使用成对点匹配来估计当前视图相对于前一个视图的相机姿态。然后,它将成对匹配链接到跨越多个视图的更长的点轨迹findTracks
方法imageviewset
对象。这些轨道然后作为输入到多视图三角测量使用triangulateMultiview
函数以及相机姿态和三维场景点的细化bundleAdjustment
函数。
该示例包括两个主要部分:摄像机运动估计和密集场景重建。在第一部分中,示例使用视图间匹配的稀疏点集估计每个视图的相机姿态。在第二部分中,示例再次遍历视图序列,使用愿景。PointTracker
来跟踪视图中密集的一组点,从而计算出场景的密集三维重建。
摄像机运动估计算法包括以下步骤:
对于每一对连续图像,找到一组点对应。方法检测兴趣点
detectSURFFeatures
方法提取特征描述符extractFeatures
方法查找匹配项matchFeatures
函数。或者,您可以使用愿景。PointTracker
.估计当前视图的相对姿态,这是相对于前一个视图的相机方向和位置。这个例子使用了一个助手函数
helperEstimateRelativePose
,它调用estimateEssentialMatrix
和estrelpose
.将当前视图的相对姿态转换为序列的第一个视图的坐标系。
存储当前视图属性:相机姿态和图像点。
存储前一个视图和当前视图之间的初始匹配。
查找到目前为止处理过的所有视图中的点轨迹。
使用
triangulateMultiview
函数来计算轨迹对应的初始三维位置。使用
bundleAdjustment
功能,以细化相机的姿势和三维点。将精致的相机姿势存储在imageviewset
对象。
读取输入图像序列
读取并显示图像序列。
%使用|imageDatastore|获取目录中所有映像文件名的列表。imageDir = fullfile(toolboxdir)“愿景”),“visiondata”,…“structureFromMotion”);imds = imageDatastore(imagedr);%显示图像。图蒙太奇(imd)。文件,“大小”, [3,2]);%将图像转换为灰度。images = cell(1, numel(imds.Files));为i = 1:numel(imds. files) i = readimage(imds, i);images{i} = im2gray(i);结束标题(“输入图像序列”);
负载摄像机参数
加载cameraParameters
对象创建的相机校准器.
data = load(fullfile(imageDir),“cameraParams.mat”));cameraParams = data.cameraParams;
创建包含第一个视图的视图集
使用一个imageviewset
对象来存储和管理与每个视图相关联的图像点和相机姿态,以及视图对之间的点匹配。一旦你在imageviewset
对象,您可以使用它来查找跨多个视图的点轨迹并检索要使用的相机姿势triangulateMultiview
和bundleAdjustment
功能。
获得相机的内在参数intrinsics = cameraParams.Intrinsics;还原第一张图片。I = untwisttimage (images{1}, intrinsics);%检测功能。增加“nummocaves”有助于检测大规模%的特征在高分辨率图像。使用ROI来消除虚假%的特征围绕图像的边缘。Border = 50;roi = [border, border, size(I, 2)- 2*border, size(I, 1)- 2*border];prevPoints = detectsurfeatures (I, nummocaves =8, ROI= ROI);%提取特性。使用“直立”特征可以改善匹配,只要摄像机的运动很少或根本不涉及平面内旋转。prevFeatures = extractFeatures(I, prevPoints, vertical =true);创建一个空的imageviewset对象来管理与每个对象相关联的数据%的观点。vSet = imageviewset;%添加第一个视图。放置与第一个视图相关联的相机%和原点,沿z轴方向。viewId = 1;vSet = addView(vSet, viewId, rigidtform3d, Points=prevPoints);
添加其余的视图
浏览剩下的图像。对于每个图像
前一个图像和当前图像之间的匹配点。
估计当前视图相对于前一个视图的相机姿态。
计算当前视图相对于第一个视图在全局坐标系中的相机姿态。
三角测量初始的3-D世界点。
使用束调整来细化所有相机姿势和3-D世界点。
为I = 2: nummel(图像)%还原当前图像。I = untwisttimage (images{I}, intrinsics);%检测、提取和匹配特征。currPoints = detectsurfeatures (I, nummocaves =8, ROI= ROI);currFeatures = extractFeatures(I, currPoints, vertical =true);indexPairs = matchFeatures(prevFeatures, currFeatures,…独特MaxRatio = 0.7, = true);%选择匹配的点。matchedPoints1 = prevPoints(indexPairs(:, 1));matchedPoints2 = currPoints(indexPairs(:, 2));估计当前视图相对于前一个视图的相机姿态。姿势是按比例计算的,这意味着两者之间的距离%前一个视图和当前视图中的摄像机设置为1。这将通过捆绑调整得到纠正。[relPose, inlierIdx] = helperEstimateRelativePose()…matchedPoints1, matchedPoints2, intrinsic);获取包含前一个相机姿势的表。prepose = pose (vSet, i-1).AbsolutePose;在全局坐标系中计算当前摄像机的姿态%相对于第一个视图。currPose = rigidtform3d(prevPose.A*relPose.A);%将当前视图添加到视图集。vSet = addView(vSet, i, currPose, Points=currPoints);%存储前一个视图和当前视图之间的点匹配。vSet = addConnection(vSet, i-1, i, relPose, Matches=indexPairs(inlierIdx,:));在所有视图中查找点轨迹。轨道= findTracks(vSet);获取包含所有视图的相机姿势的表。campose = pose (vSet);对3-D世界点的初始位置进行三角测量。xyzPoints = triangulateMultiview(tracks, campose, intrinsics);细化3-D世界的点和相机姿势。[xyzPoints, campose, reprojectionErrors] = bundleadadjustment (xyzPoints, reprojectionErrors)…tracks, campose, intrinsics, FixedViewId=1,…PointsUndistorted = true);储存精致的相机姿势。vSet = updateView(vSet, campose);prevFeatures = currFeatures;prevPoints = currPoints;结束
展示相机姿势
显示精致的相机姿势和三维世界点。
%显示相机姿势。campose = pose (vSet);图;plotCamera(坎波斯,大小= 0.2);持有在%排除嘈杂的3-D点。goodIdx = (reprojectionErrors < 5);xyzPoints = xyzPoints(goodIdx,:);%显示3d点。pcshow (xyzPoints VerticalAxis =“y”VerticalAxisDir =“下来”, marksize = 45);网格在持有从%指定查看卷。loc1 = camPoses.AbsolutePose(1).Translation;xlim ([loc1 (1) 5, loc1 (1) + 4]);ylim ([loc1 (2) 5, loc1 (2) + 4]);zlim ([loc1 (3) 1, loc1 (3) + 20));camorbit (0, -30);标题(“精致的拍照姿势”);
计算密集重构
再看一遍图片。这一次检测密集的角集,并在所有视图中使用愿景。PointTracker
.
读取并还原第一张图片I = untwisttimage (images{1}, intrinsics);%检测第一张图像中的角。prepoints = detectMinEigenFeatures(I, MinQuality=0.001);创建点跟踪器对象来跟踪视图中的点。追踪者=视觉。PointTracker(MaxBidirectionalError=1, NumPyramidLevels=6);初始化点跟踪器。prevPoints = prevPoints. location;initialize(tracker, prevPoints, I);将密集点存储在视图集中。vSet = updateConnection(vSet, 1,2, Matches= 0 (0,2));vSet = updateView(vSet, 1, Points=prevPoints);跟踪所有视图中的点。为I = 2: nummel(图像)读取并还原当前图像。I = untwisttimage (images{I}, intrinsics);跟踪这些点。[currPoints, valididdx] = step(tracker, I);清除点之间的旧匹配。如果i < nummel (images) vSet = updateConnection(vSet, i, i+1, Matches= 0 (0,2));结束vSet = updateView(vSet, i, Points=currPoints);将点匹配存储在视图集中。match = repmat((1:size(prevPoints, 1))', [1,2]);matches = matches(valididdx,:);vSet = updateConnection(vSet, i-1, i, Matches= Matches);结束在所有视图中查找点轨迹。轨道= findTracks(vSet);在所有视图中查找点轨迹。campose = pose (vSet);对3-D世界点的初始位置进行三角测量。xyzPoints = triangulateMultiview(tracks, campose,…intrinsic);细化3-D世界的点和相机姿势。[xyzPoints, campose, reprojectionErrors] = bundleadadjustment (…xyzPoints, tracks, campose, intrinsics, FixedViewId=1,…PointsUndistorted = true);
显示密集重建
显示相机姿势和密集的点云。
显示精致的相机姿势。图;plotCamera(坎波斯,大小= 0.2);持有在%排除嘈杂的3d世界点。goodIdx = (reprojectionErrors < 5);%显示密集的三维世界点。pcshow(xyzPoints(goodIdx,:), VerticalAxis=“y”VerticalAxisDir =“下来”MarkerSize = 45);网格在持有从%指定查看卷。loc1 = camPoses.AbsolutePose(1).Translation;xlim ([loc1 (1) 5, loc1 (1) + 4]);ylim ([loc1 (2) 5, loc1 (2) + 4]);zlim ([loc1 (3) 1, loc1 (3) + 20));camorbit (0, -30);标题(“密集的重建”);
参考文献
[10] M.I.A. Lourakis和A.A. Argyros(2009)。SBA:一个通用稀疏束调整软件包。数学软件学报,36(1):1-30。
R. Hartley, A. Zisserman,“计算机视觉中的多视图几何”,剑桥大学出版社,2003年。
B.特里格斯;p . McLauchlan;r·哈特利;A.菲茨吉本(1999)。“束调整:现代综合”。视觉算法国际研讨会论文集。斯普林格出版社。298 - 372页。