主要内容

单目视觉里程计

视觉测程是通过分析一系列图像来确定相机的位置和方向的过程。视觉测程技术被广泛应用于移动机器人、自动驾驶汽车和无人机等领域。这个例子向您展示了如何从一系列图像中估计单个校准相机的轨迹。

概述

这个例子展示了如何从一系列2-D视图中估计校准相机的轨迹。这个例子使用了筑波大学CVLAB创建的新筑波立体数据集的图像。(https://cvlab.cs.tsukuba.ac.jp)。该数据集由合成图像组成,使用计算机图形生成,并包括地面真实相机姿势。

如果没有额外的信息,单目相机的轨迹只能恢复到一个未知的比例因子。用于移动机器人或自动驾驶车辆的单目视觉里程计系统通常从另一个传感器(例如车轮里程计或GPS)或场景中已知大小的物体获取比例因子。这个例子从基本事实计算比例因子。

本例分为三个部分:

  1. 估计第二个视图相对于第一个视图的姿态。通过估计基本矩阵并将其分解为相机位置和方向来估计第二个视图的姿态。

  2. 使用全局包调整自引导估计相机轨迹。利用极坐标约束消除异常值。找到从前两个视图和当前视图三角化的点之间的3d到2d对应关系。通过解决透视n点(PnP)问题,计算当前视图的世界摄像机姿态。估计相机姿势不可避免地会产生错误,这些错误会随着时间的推移而累积。这种效应叫做的漂移.为了减少漂移,该示例使用束调整优化了迄今为止估计的所有姿势。

  3. 估计剩余的相机轨迹使用窗口束调整。随着每一个新的视图,它所需要的时间来完善所有的姿势增加。窗口包调整是一种通过只优化最后一个来减少计算时间的方法n视图,而不是整个轨迹。不为每个视图调用包调整,从而进一步减少了计算时间。

读取输入图像序列和Ground Truth

类中的图像新的筑波立体数据集由筑波大学的CVLAB创建。如果您在自己的作品或出版物中使用这些图像,请引用以下论文:

[1] Martin Peris Martorell, Atsuto Maki, Sarah Martull, Yasuhiro Ohkawa, Kazuhiro Fukui,“朝着模拟驱动的立体视觉系统”。《国际刑事司法学报》,2012,pp.1038-1042。

[2] Sarah Martull, Martin Peris Martorell, Kazuhiro Fukui,“基于地面真相视差地图的真实CG立体图像数据集”,ICPR研讨会会议记录,第40-42页,2012。

图片= imageDatastore(fullfile(toolboxdir(“愿景”),“visiondata”“NewTsukuba”));%加载地面真相相机姿势。负载(“visualOdometryGroundTruth.mat”

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

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

创建一个空的imageviewset对象来管理与每个视图相关的数据。vSet = imageviewset;读取并显示第一个图像。Irgb = readimage(images, 1);玩家=视野。VideoPlayer(Position=[20,400,650,510]);步骤(球员,Irgb);

{

类中的相机intrinsic对象创建相机intrinsic对象%新的Tsukuba数据集。focalLength = [615 615];%以像素为单位指定principalPoint = [320 240];%(像素[x, y])imageSize = size(Irgb,[1,2]);%(像素)[mrows, ncols]intrinsic = cameraIntrinsics(focalLength, principalPoint, imageSize);

转换为灰度和不扭曲。在这个例子中,不失真没有效果,因为图像是合成的,没有镜头失真。然而,对于真实的图像,不失真是必要的。

prevI = undistortion timage (im2gray(Irgb), intrinsic);检测特征。prevPoints = detectsurffatures (prevI, MetricThreshold=500);选择特征的子集,均匀分布在整个图像中。numPoints = 200;prevPoints = selectUniform(prevPoints, numPoints, size(prevI));提取特征。使用“直立”功能可以提高匹配质量相机运动涉及很少或没有平面内旋转。。prevFeatures = extractFeatures(prevI, prevPoints,直立=true);添加第一个视图。将相机与第一个视图相关联%在原点,沿z轴方向。viewId = 1;vSet = addView(vSet, viewId, rigidtform3d(eye(3), [0 0 0 0]), Points=prevPoints);

图初始拍照姿势

根据New Tsukuba数据集的地面真实数据,创建两个图形相机对象,表示估计的和实际的相机姿势。

%设置轴。图轴([-220,50,-140,20,-50,300]);设置y轴为垂直向下。甘氨胆酸视图(3);set(gca, CameraUpVector=[0, - 1,0]);Camorbit (gca, -120, 0, data=[0,1,0]);网格包含(“X (cm)”);ylabel (“Y (cm)”);zlabel (“Z (cm)”);持有绘制估计的相机姿势。cameraSize = 7;camPose =姿势(vSet);camestimate = plotCamera(camPose, Size=cameraSize,...颜色=“g”,透明度= 0);绘制实际相机姿势。camActual = plotCamera(大小=cameraSize,...AbsolutePose = rigidtform3d (groundTruthPoses。取向{1}”,...groundTruthPoses.Location {1}),...颜色=“b”,透明度= 0);初始化相机轨迹。轨迹估计= plot3(0,0,0,“g -”);轨迹实际= plot3(0,0,0,“b -”);传奇(“估计轨迹”“实际轨迹”);标题(“相机轨迹”);

图中包含一个轴对象。标题为Camera Trajectory的axis对象包含22个类型为line、text、patch的对象。这些对象表示估计轨迹、实际轨迹。

估计第二个视图的姿态

从第二个视图中检测和提取特征,并将它们与第一个视图匹配helperDetectAndMatchFeatures.估计第二个视图相对于第一个视图的姿态helperEstimateRelativePose,并将其添加到imageviewset

读取并显示图像。viewId = 2;Irgb = readimage(图像,viewId);步骤(球员,Irgb);

{

%转换为灰度和不扭曲。I = undistortion timage (im2gray(Irgb), intrinsic);匹配上一个图像和当前图像之间的特征。[currPoints, currFeatures, indexPairs] = helperDetectAndMatchFeatures(...prevFeatures,我);估计当前视图相对于前一个视图的姿态。[relPose, inlierIdx] = helperEstimateRelativePose(...prevPoints(indexPairs(:,1)), currPoints(indexPairs(:,2)), intrinsic);排除极外离群值。indexPairs = indexPairs(inlierIdx,:);将当前视图添加到视图集中。vSet = addView(vSet, viewId, relPose, Points=currPoints);存储前一个视图和当前视图之间的匹配点。vSet = addConnection(vSet, viewId-1, viewId, Matches=indexPairs);

第二个视图相对于第一个视图的位置只能恢复到一个未知的比例因子。计算比例因子从地面真相使用helperNormalizeViewSet,模拟一个外部传感器,这将用于典型的单目视觉里程计系统。

vSet = helperNormalizeViewSet(vSet, groundtruthpositions);

更新相机轨迹图使用helperUpdateCameraPlots而且helperUpdateCameraTrajectories

helperUpdateCameraPlots(viewId, camEstimated, camActual, pose (vSet),...groundTruthPoses);helperUpdateCameraTrajectories(viewId,轨迹估计,轨迹实际,...姿势(vSet) groundTruthPoses);

图中包含一个轴对象。标题为Camera Trajectory的axis对象包含22个类型为line、text、patch的对象。这些对象表示估计轨迹、实际轨迹。

prevI = I;prevFeatures = currFeatures;prevPoints = currPoints;

使用全局包调整的Bootstrap估计摄像机轨迹

找到从前两个视图三角化的世界点和当前视图的图像点之间的3d到2d对应关系。使用helperFindEpipolarInliers找到满足极坐标约束的匹配项,然后使用helperFind3Dto2DCorrespondences将前两个视图中的三维点三角化,并在当前视图中找到相应的二维点。

通过求解透视n点(PnP)问题,计算当前视图的世界摄像机姿态estworldpose.对于前15个视图,使用全局bundle调整来细化整个轨迹。对于有限数量的视图使用全局捆绑调整引导估计相机轨迹的其余部分,并且它不是非常昂贵。

viewId = 3:15读取并显示下一个图像Irgb = readimage(图像,viewId);步骤(球员,Irgb);%转换为灰度和不扭曲。I = undistortion timage (im2gray(Irgb), intrinsic);%前一个图像和当前图像之间的匹配点。[currPoints, currFeatures, indexPairs] = helperDetectAndMatchFeatures(...prevFeatures,我);从特征匹配中消除异常值。[~, inlierIdx] = helperEstimateRelativePose(prevPoints(indexPairs(:,1)),...currPoints(indexPairs(:, 2)), intrinsic);indexPairs = indexPairs(inlierIdx,:);%对前两个视图中的点进行三角剖分,并找到%当前视图中的对应点。[worldPoints, imagePoints] = helperfind3dto2dresponses (vSet,...intrinsic, indexPairs, currPoints);由于RANSAC涉及随机过程,有时可能不是达到所期望的置信水平,并超过的最大数目%试验。当发生这种情况时禁用警告,因为结果是%仍然有效。Warningstate =警告(“关闭”“愿景:ransac: maxTrialsReached”);估计当前视图的世界相机姿态。absPose = estworldpose(imagePoints, worldPoints, intrinsic);恢复原始警告状态警告(warningstate)将当前视图添加到视图集中。vSet = addView(vSet, viewId, absPose, Points=currPoints);存储前一个视图和当前视图之间的匹配点。vSet = addConnection(vSet, viewId-1, viewId, Matches=indexPairs);tracks = findTracks(vSet);查找跨越多个视图的点轨迹。camposed = pose (vSet);获取所有视图的相机姿势。三角化三维世界点的初始位置。。xyzPoints = triangulateMultiview(轨迹,campose, intrinsic);使用束调整优化相机姿势。[~, campose] = bundleadadjustment (xyzPoints, tracks, campose,...intrinsic, pointsundistortion =true, AbsoluteTolerance=1e-12,...RelativeTolerance=1e-12, MaxIterations=200, FixedViewID=1);vSet = updateView(vSet, camposed);%更新视图集。捆绑调整可以移动整套相机。规范化的%视图设置,将第一个摄像机放在原点沿% z轴,并调整比例以匹配地面真相。vSet = helperNormalizeViewSet(vSet, groundtruthpositions);更新相机轨迹图。helperUpdateCameraPlots(viewId, camEstimated, camActual, pose (vSet),...groundTruthPoses);helperUpdateCameraTrajectories (viewId trajectoryEstimated,...轨迹实际,pose (vSet), groundtruthpose);prevI = I;prevFeatures = currFeatures;prevPoints = currPoints;结束

图中包含一个轴对象。标题为Camera Trajectory的axis对象包含22个类型为line、text、patch的对象。这些对象表示估计轨迹、实际轨迹。

{

估计剩余的相机轨迹使用窗口束调整

通过使用带窗口的束调整来估计剩余的摄像机轨迹,只细化最后15个视图,以限制计算量。此外,不必为每个视图调用包调整,因为estworldpose以与三维点相同的单位计算姿态。本节为每7个视图调用bundle调整。实验选择了窗口大小和调用束调整频率。

viewId = 16:numel(images.Files)读取并显示下一个图像Irgb = readimage(图像,viewId);步骤(球员,Irgb);%转换为灰度和不扭曲。I = undistortion timage (im2gray(Irgb), intrinsic);%前一个图像和当前图像之间的匹配点。[currPoints, currFeatures, indexPairs] = helperDetectAndMatchFeatures(...prevFeatures,我);%对前两个视图中的点进行三角剖分,并找到%当前视图中的对应点。[worldPoints, imagePoints] = helperfind3dto2dresponses (vSet,...intrinsic, indexPairs, currPoints);由于RANSAC涉及随机过程,有时可能不是达到所期望的置信水平,并超过的最大数目%试验。当发生这种情况时禁用警告,因为结果是%仍然有效。Warningstate =警告(“关闭”“愿景:ransac: maxTrialsReached”);估计当前视图的世界相机姿态。absPose = estworldpose(imagePoints, worldPoints, intrinsic);恢复原始警告状态警告(warningstate)将当前视图和连接添加到视图集中。vSet = addView(vSet, viewId, absPose, Points=currPoints);vSet = addConnection(vSet, viewId-1, viewId, Matches=indexPairs);使用窗口束调整优化估计的相机姿势。运行%优化每7个视图。如果mod(viewId, 7) == 0在最近15个视图中找到点轨迹并进行三角测量。windowSize = 15;startFrame = max(1, viewId - windowSize);tracks = findTracks(vSet, startFrame:viewId);campositions = pose (vSet, startFrame:viewId);[xyzPoints, retrjerrors] = triangulateMultiview(轨迹,campose, intrinsic);保持前两个姿势不变,保持相同的比例。。fixedIds = [startFrame, startFrame+1];排除重投影误差大的点和轨迹。idx = retrjerrors < 2;[~, camposed] = bundleadadjustment (xyzPoints(idx,:), tracks(idx),...campose, intrinsic, FixedViewIDs=fixedIds,...PointsUndistorted = true, AbsoluteTolerance e-12 = 1,...RelativeTolerance = 1 e-12 MaxIterations = 200);vSet = updateView(vSet, camposed);%更新视图集。结束更新相机轨迹图。helperUpdateCameraPlots(viewId, camEstimated, camActual, pose (vSet),...groundTruthPoses);helperUpdateCameraTrajectories (viewId trajectoryEstimated,...轨迹实际,pose (vSet), groundtruthpose);prevI = I;prevFeatures = currFeatures;prevPoints = currPoints;结束

{

持有

图中包含一个轴对象。标题为Camera Trajectory的axis对象包含22个类型为line、text、patch的对象。这些对象表示估计轨迹、实际轨迹。

总结

本例展示了如何从一系列视图中估计校准单目摄像机的轨迹。请注意,估计的轨迹并不完全符合实际情况。尽管对相机姿态进行了非线性细化,但相机姿态估计中的误差不断累积,导致漂移。在视觉里程计系统中,这个问题通常通过融合来自多个传感器的信息和执行闭环来解决。

参考文献

[1] Martin Peris Martorell, Atsuto Maki, Sarah Martull, Yasuhiro Ohkawa, Kazuhiro Fukui,“朝着模拟驱动的立体视觉系统”。《国际刑事司法学报》,2012,pp.1038-1042。

[2] Sarah Martull, Martin Peris Martorell, Kazuhiro Fukui,“基于地面真相视差地图的真实CG立体图像数据集”,ICPR研讨会会议记录,第40-42页,2012。

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

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

[5] B. Triggs;p . McLauchlan;r·哈特利;A. Fitzgibbon(1999)。“束调整:现代综合”。视觉算法国际研讨会论文集。斯普林格出版社。298 - 372页。

[6] X.-S。高,X.-R。侯杰,唐俊华。程,“视角-三点问题的完整解决方案分类”,IEEE Trans。模式分析与机器智能,第25卷,no。8, pp. 930-943, 2003。