最近整理了下金字塔的相关知识,做出如下思考:
下面是ORBSLAM2提取特征点的效果0-7层金字塔,这里只展示了0-7层全部特征点,仅第0、2、5、7层特征点,可以看到有种离着桌子越来越远的感觉(近大远小)。原始图中红色的可乐易拉罐瓶上有很多特征点,在但在第7层的金字塔图像上整个瓶底就是一个特征点,这符合我们正常的视觉。但是这里的视野没有变的越来越大,这是因为金字塔图像是仅是经过下采样得到,而不是真实的相机后退。
思考问题1:图像金字塔的尺度不变性体现在哪里?
我们常常理解的尺度不变性是指一个东西我近看是它远看还是它。图像金字塔的尺度不变性也以理解为一个场景的尺度不变性,由于特征点本身(一个坐标点)和相机本身(2D)的特性,我们无法做到一个特征点近看是特征点,远看也是特征点。这里的尺度不变性是局部且动态(以金字塔层位单位)来描述的,而不是针对单一的特征点。
假设我们在前后两帧的匹配都是用上一帧来匹配当前帧,当前帧相对上一帧有前进,后退和原地不动三种状态。
原地不动:可以在相同层附近匹配
前进:
如果我们在L拍完了往前走到C点,那L中的特征点要到C的较高层金字塔中寻找匹配,L0->C1,L1->C2,L2->C3(L表示上一帧,C表示当前帧)
后退:
比如:如图我在L点拍了一帧场景图像,后退走到了C点,那么我能用L点拍摄的图像的较高金字塔来匹配C点较低层的特征点。 L1->C0,L2->C1,L3->C2..
下面是ORBSLAM2用上一帧地图点投影到当前帧进行匹配的搜索决策
if(bForward) // 前进,到当前帧更高金字塔层搜索
vIndices2 = CurrentFrame.GetFeaturesInArea(u,v, radius, nLastOctave);//找到nLastOctave层到最高层的特征点
else if(bBackward) // 后退,到当前帧更低的金字塔层搜索
vIndices2 = CurrentFrame.GetFeaturesInArea(u,v, radius, 0, nLastOctave);//找到第0层到nLastOctave层的特征点
else // 在[nLastOctave-1, nLastOctave+1]中搜索 上一层 本层 下一层 三层中搜索
vIndices2 = CurrentFrame.GetFeaturesInArea(u,v, radius, nLastOctave-1, nLastOctave+1);
思考问题2:不同金字塔层提取的特征点
都放在第0层合理吗?
说明: ,k=1表示LastFrame,K=2表示CurrentFrame, j表示第几层金字塔的特征点。这里用4层作为例子。
这里我们先假设LastFrame的每层金字塔层都只提取了一个特征点如图绿色点所示,CurrentFrame同理如图蓝色点所示,且两帧所有不同金字塔层的特征点都匹配上了。
在匹配之前,我们将不同金字塔层的特征点按层逐一提取后,全部乘以对应的系数放在了第0层,这样我们在后面的匹配,求位姿等就可以统一处理。那么这样做合理吗?
我们可以将除了第0层之外的特征点全部当成一个假想的特征点(其实就是一个特殊的坐标),如上图所示,虽然从成像来看,由于远处的物体运动的慢,近处的物体运动的快(体现在像素点变化个数),但是我们都乘以一个缩放尺度,这样使得原本在第七层运动了2个像素回到第0层就是个像素。说白了就是在第七层如果特征点在桌角,伸缩到原始图像上特征点也在桌角上。第七层中若特征点从A像素移动到B像素,对应原始图像则从A1运动到B1。这是完全对应的,由于金字塔层数越高,其一个特征点所包含的场景越大,使得其特征点回归到0层的误差越大。这么分析过后就可以假想所有的特征点都是在第0层提取的一样。只是后面在计算位姿考虑精度的问题,考虑不同层提取的特征点所对应的误差不一样。
思考问题3:RGBD相机直接用第0层的特征点恢复出地图点合理吗?
声明:为了方便描述,称在其他层提取特征点变换到第0层的像素坐标,但第0层的这个像素坐标不是特征点为假想特征点。分析见上面问题。
由于前面的分析可以明确,比如A帧中假想特征点其自带在别的层提取的描述子。且在别的帧中第0层中也回存在假想特征点及其描述子与A中的假想特征点进行匹配,所以可以直接对假想特征点获取3D深度当成一个地图点。本质上来说,提取的就是原始图像的xy和对应深度的z,而金字塔等种种操作都是为了维护这个原始图像的x和y,所以如此算出的位姿也是正确的。
再举个例子加深理解;(在计算地图点的距离范围用到)
cv::Mat PC = Pos - Ow;//地图点坐标用都是用相机本体坐标系计算(和金字塔无关)
const float dist = cv::norm(PC); //地图点到相机的距离
const int level = pFrame->mvKeysUn[idxF].octave; //获取该地图点的金字塔层
const float levelScaleFactor = pFrame->mvScaleFactors[level];
const int nLevels = pFrame->mnScaleLevels;
mfMaxDistance = dist*levelScaleFactor; //地图点能观测的最大距离(指的是地图点到相机的距离)
mfMinDistance = mfMaxDistance/pFrame->mvScaleFactors[nLevels-1]; //地图点能观测的最小距离
如(1)所示,这里假设地图点在金字塔的第五层被观测到,这时候dis等于世界坐标系下地图点的坐标到相机坐标的范数。因为地图点坐标(无论哪层观测)都是相机本体的坐标计算,实际上地图点的距离还和观测到的金字塔层数有关系,所以这里可以设置地图点存在的最大距离和最小距离。
如(2)所示,maxdis等于dis乘以地图点所在金字塔层系数,表示如果相机本体在这个位置,则相机再往后退,任何层都不能观测到该地图点。
如(3)所示,mindis等于maxdis/7层金字塔的缩放系数,表示如果相机再往前走,则金字塔最远观测层第七层也无法看到该地图点。
以上分析如果有理解错误,欢迎交流指正。转载请注明。