1.图像金字塔
在orb_slam2中,为了实现特征尺度不变性采用了图像金字塔,金字塔的缩放因子为1.2,。其思路就是对原始图形(第0层)依次进行1/1.2缩放比例进行降采样得到共计8张图片(包括原始图像),
来说说,尺度不变性,这里不直接说明,而是看看对于第m层上的一个特征点,其对应尺度不变时相机与特征点对应空间位置之间距离(简称物距)的范围。
2.代码:
// ____
// Neare /____\ level:n-1 --> dmin
// /______\ d/dmin = 1.2^(n-1-m)
// /________\ level:m --> d
// /__________\ dmax/d = 1.2^m
// Farther /____________\ level:0 --> dmax
//
// log(dmax/d)
// m = ceil(-------------------)
// log(1.2)
对应代码为:
//更新地图点被观察的平均方向和观测距离范围
void MapPoint::UpdateNormalAndDepth()
{
map<KeyFrame*,size_t> observations;
KeyFrame* pRefKF;
cv::Mat Pos;
{
unique_lock<mutex> lock1(mMutexFeatures);
unique_lock<mutex> lock2(mMutexPos);
if(mbBad)
return;
observations=mObservations; //获得观测到该3d点的所有关键帧
pRefKF=mpRefKF; //观测到该点的参考关键帧
Pos = mWorldPos.clone(); //3d点在世界坐标系中的位置
}
if(observations.empty())
return;
cv::Mat normal = cv::Mat::zeros(3,1,CV_32F);
int n=0;
for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++)
{
KeyFrame* pKF = mit->first;
cv::Mat Owi = pKF->GetCameraCenter();
cv::Mat normali = mWorldPos - Owi;
normal = normal + normali/cv::norm(normali); //对所有关键帧对该点的观测方向做归一化并求和
n++;
}
cv::Mat PC = Pos - pRefKF->GetCameraCenter(); //从参考关键帧观察该地图点的向量
const float dist = cv::norm(PC); //地图点到参考关键帧相机中心的距离
const int level = pRefKF->mvKeysUn[observations[pRefKF]].octave;
const float levelScaleFactor = pRefKF->mvScaleFactors[level];
const int nLevels = pRefKF->mnScaleLevels; //金字塔层数
{
unique_lock<mutex> lock3(mMutexPos);
//详情请见PredictScale函数前的注释
mfMaxDistance = dist*levelScaleFactor; //计算最大尺度
mfMinDistance = mfMaxDistance/pRefKF->mvScaleFactors[nLevels-1]; //计算最小尺度
mNormalVector = normal/n; //计算平均观测方向
}
}
疑点:
1.初始化得到了尺度,这个尺度通过PnP技术依次传递,也就是说初始尺度是基准参考,故初始化很重要
2.尺度统一应该是前两帧使用对积几何知识解算出位姿,后边的位姿使用PnP技术,避免分解基础矩阵或单应矩阵,让尺度统一
3.可以认为它没有单位,也无法计算出和真实尺度的比例,要是能计算这个比例,就不存在尺度无法计算的问题了。
参考: