前面几帧的处理都是为初始化做准备,到第八帧才满足进行初始化的条件。
第八帧
前面直到else if(coarseInitializer->trackFrame(fh, outputWrapper))
的处理均与第2帧一样,在当前帧的时候,对第一帧进行跟踪之后会返回ture,表示可以进行初始化操作。
初始化操作:
initializeFromInitializer(fh);
initializeFromInitializer(fh)
函数解析:
1.添加第一帧:
FrameHessian* firstFrame = coarseInitializer->firstFrame;
firstFrame->idx = frameHessians.size();
frameHessians.push_back(firstFrame);
firstFrame->frameID = allKeyFramesHistory.size();
allKeyFramesHistory.push_back(firstFrame->shell);
在这里新定义vector:frameHessians
和allKeyFramesHistory
,并把第一帧加入进去,(这两个容器应该是只存储关键帧的相关信息,此时里面仅有第一帧)
2.第一帧加入优化:
ef->insertFrame(firstFrame, &Hcalib);
setPrecalcValues();
利用ef->insertFrame(firstFrame, &Hcalib)
,将第一帧加入到优化后端energyFunction
,加入过程为:创建当前帧的EFFrame
对象eff,并将其加入到vector:frames
,同时将表示energyFunction
中图像帧数量的nFrames
加1(用来确定优化变量的维数,每个图像帧是8维),并且建立当前帧和eff 的关联:fh->efFrame = eff;
,然后执行setAdjointsF();
和makeIDX();
利用setAdjointsF(Hcalib);
建立两帧之间的相对状态对主导帧和目标帧的状态的求导。(因为优化的变量是各帧的绝对状态而不是相对状态,在后面的滑窗优化中会使用到)建立方法为:定义两个数组,分别用来存储主导帧和目标帧,adHost = new Mat88[nFrames*nFrames]; adTarget = new Mat88[nFrames*nFrames];
然后会传递给数组adHostF
和adTargetF
,这里是会建立尽可能多的主导帧和目标帧的关联,即遍历所有帧,将所有帧作为当前帧的目标帧。
利用makeIDX();
将点加入到vector:allPoints
,然后建立residual的主导帧id和目标帧id,但是此时未在第一帧中加入点。建立过程为:遍历EFFrame,遍历EFPoint,加入到vector:allPoints
,遍历EFResidual,建立hostIDX和targetIDX。
在setPrecalcValues();
会建立所有帧的目标帧,并且进行主导帧和目标帧之间相对状态的预计算,实现的函数见下,计算的量有:leftToLeft
,PRE_RTll
,PRE_tTll
,PRE_KRKiTll
,PRE_RKiTll
,PRE_KtTll
,PRE_aff_mode
,PRE_b0_mode
。
fh->targetPrecalc[i].set(fh, frameHessians[i], &Hcalib);
然后利用:ef->setDeltaF(&Hcalib);
建立相关量的微小扰动,包括:adHTdeltaF[idx]
,f->delta
,f->delta_prior
。
3.初始第一帧的各种点,包括:pointHessians
,pointHessiansMarginalized
,pointHessiansOut
。
firstFrame->pointHessians.reserve(wG[0]*hG[0]*0.2f);
firstFrame->pointHessiansMarginalized.reserve(wG[0]*hG[0]*0.2f);
firstFrame->pointHessiansOut.reserve(wG[0]*hG[0]*0.2f);
4.利用前面帧对第一帧的跟踪更新的逆深度,计算尺度因子rescaleFactor
(相对的),并且根据相关参数设置第一帧保持的点的数目:keepPercentage
。
float sumID=1e-5, numID=1e-5;
for(int i=0;i<coarseInitializer->numPoints[0];i++)
{
sumID += coarseInitializer->points[0][i].iR;
numID++;
}
float rescaleFactor = 1 / (sumID / numID);
5.将第一帧的未成熟点生成PointHessian
,并且设置PointHessian
的相关参数,存储到第一帧的容器pointHessians
中,然后利用insertPoint()
加入到后端优化中。注意:前面分析对第一帧选点时说到是在每层图像金字塔都会进行选点,但是此时生成PointHessian
仅利用第0层(即原始图像层)选取的点。
在应用构造函数创建类ImmaturePoint
的对象pt
时,会计算点的权重:weights[idx]
。
Pnt* point = coarseInitializer->points[0]+i;
ImmaturePoint* pt = new ImmaturePoint(point->u+0.5f,point->v+0.5f,firstFrame,point->my_type, &Hcalib);
if(!std::isfinite(pt->energyTH)) { delete pt; continue; }
pt->idepth_max=pt->idepth_min=1;
PointHessian* ph = new PointHessian(pt, &Hcalib);
delete pt;
if(!std::isfinite(ph->energyTH)) {delete ph; continue;}
ph->setIdepthScaled(point->iR*rescaleFactor);
ph->setIdepthZero(ph->idepth);
ph->hasDepthPrior=true;
ph->setPointStatus(PointHessian::ACTIVE);
firstFrame->pointHessians.push_back(ph);
ef->insertPoint(ph);
在insertPoint()
中会生成PointHessian
类型的点ph
的EFPoint
类型的efp
,efp
,包含点ph
以及其主导帧host
。按照push_back
的先后顺序对idxInPoints
进行编号, nPoints
表示后端优化中点的数量。
EFPoint* efp = new EFPoint(ph, ph->host->efFrame);
efp->idxInPoints = ph->host->efFrame->points.size();
ph->host->efFrame->points.push_back(efp);
nPoints++;
ph->efPoint = efp;
6.通过前面所有帧对第一帧的track以及optimization得到第一帧到第八帧的位姿:firstToNew
,并对平移部分利用尺度因子进行处理。
SE3 firstToNew = coarseInitializer->thisToNext;
firstToNew.translation() /= rescaleFactor;
7.设置第一帧和第八帧的相关参数。
firstFrame->shell->camToWorld = SE3();
firstFrame->shell->aff_g2l = AffLight(0,0);
firstFrame->setEvalPT_scaled(firstFrame->shell->camToWorld.inverse(),firstFrame->shell->aff_g2l);
firstFrame->shell->trackingRef=0;
firstFrame->shell->camToTrackingRef = SE3();
newFrame->shell->camToWorld = firstToNew.inverse();
newFrame->shell->aff_g2l = AffLight(0,0);
newFrame->setEvalPT_scaled(newFrame->shell->camToWorld.inverse(),newFrame->shell->aff_g2l);
newFrame->shell->trackingRef = firstFrame->shell;
newFrame->shell->camToTrackingRef = firstToNew.inverse();
8.初始化成功:initialized=true;
至此初始化已经成功了,接下的操作是将第八帧作为关键帧进行处理。
利用deliverTrackedFrame(fh, true)对当前图像帧处理,实现关键帧和非关键帧的区分(当前为true,将当前帧作为关键帧进行处理)
if(needKF) makeKeyFrame(fh);
(感觉再接着写下去,博客会过长,接下一篇博客吧!)