日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

DSO窗口优化部分代码注释加理论解析

發(fā)布時間:2023/12/20 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 DSO窗口优化部分代码注释加理论解析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

總綱:

float FullSystem::optimize(int mnumOptIts)
{
? ?0.先清空活動點殘差隊列
? ?1.將所有外面舊成熟點相對新幀計算的殘差和新成熟點相對非所在關鍵幀的殘差加入點的殘差隊列
? ?2.調用linearizeAll()函數(shù)計算相關導數(shù)。
? ?調用linearizeAll()
? ?{
? ? ? ?2.1 linearizeAll_Reductor()
? ? ? ? ? ?{
? ? ? ? ? ? ?linearize()
? ? ? ? ? ? ? {
? ? ? ? ? ? ?具體活在這里干。完成的功能有:給點的state_NewState屬性賦值,計算點的各種雅克比行列式
? ? ? ? ? ? ?所需偏導,這些偏導是組成最終方程矩陣的基本元素。函數(shù)的返回結果是此點的殘差值。
? ? ? ? ? ? ?}
? ? ? ? ? ? }
? ? ? ?2.2 調用一次setNewFrameEnergyTH修改什么閾值。
? ? ? ?2.3 剔除判為外點的殘差。
? ?}
? ?3.調用applyRes_Reductor函數(shù),這個函數(shù)對好點做一次中間量的計算,輸入數(shù)據(jù)可看成是linearize返回的偏導值,
? ? ? 所謂輸出的中間量就是例如:殘差對位姿的偏導的轉置* 殘差對逆深度的偏導等這類的東西。
? ? ? 最后會在solveSystem函數(shù)里用到這些中間變量,其實所謂中間變量就是雅克比矩陣的一些組成元素。
? ?4.開始迭代優(yōu)化
?? ? for()
?? ? {
?? ??? ? 4.1 保存當前的狀態(tài),這是為了在優(yōu)化結果不好的情況下可以回退,backupState函數(shù)實現(xiàn)。
?? ??? ? 4.2 求解優(yōu)化增量方程 解出的結果有68包含的各項的小增量,所有點深度值的小增量。都
?? ??? ? ? ? 是絕對增量值切記切記,solveSystem函數(shù)實現(xiàn)
?? ??? ? ? ? {
?? ??? ? ? ? ? ? 4.2.1 getNullspaces 零空間申請
?? ??? ? ? ? ? ? 4.2.2 solveSystemF 真正的解方程的位置
?? ??? ? ? ? ? ? ? ? ? {
?? ??? ? ? ? ? ? ? ? ??
?? ??? ? ? ? ? ? ? ? ? ? ?4.2.2.1 計算舒爾消元方程的那些系數(shù) 用到2.1步驟中計算的值以及3步驟計算的值。然后解出第一個方程
?? ??? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 關于位姿和仿射以及相機參數(shù)的方程的解。獲得68 個增量值(8幀的關鍵幀窗口的話)
?? ??? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?? ??? ? ? ? ? ? ? ? ? ? ?4.2.2.2 根據(jù)上面的解計算解出逆深度方程的解。 獲得逆深度值們的增量
?? ??? ? ? ? ? ? ? ? ? ? ?
?? ??? ? ? ? ? ? ? ? ? ? ?4.2.2.3 零空間做一次修正
?? ??? ? ? ? ? ? ? ? ? }
?? ??? ? ? ? }
?? ??? ? 4.3 對計算的增量進一步限制次數(shù)
?? ??? ? 4.4 doStepFromBackup()
?? ??? ? ? ? {
?? ??? ? ? ? ? ?4.4.1 用增量更新關鍵幀窗口中的各項狀態(tài)值,如位姿,仿射,相機參數(shù),點的逆深度等。輸入為4.2.2.1 ?4.2.2.2這兩步結果
?? ??? ? ? ? ? ?4.4.2 ?setPrecalcValues 將兩幀之間的優(yōu)化前后狀態(tài)值(不包括點的逆深度值)都存儲一份。
?? ??? ? ? ? ? ? ? ? ?然后計算一下狀態(tài)值的增量值(包括逆深度值)
?? ??? ? ? ? }
?? ??? ? 4.5 用上面計算得到的新狀態(tài)值計算一次新的殘差以及偏導數(shù)等,在linearizeAll中實現(xiàn)。
?? ??? ? 4.6 如果新殘差值小于原來殘差值,那么就再調用一次調用applyRes_Reductor函數(shù),接著調整lambda值,
?? ??? ? 再返回到4.1,接著順序執(zhí)行。否則就將狀態(tài)結果回退,升高lambda值返回4.1順序執(zhí)行。
?? ??? ? 4.7 滿足迭代跳出條件后結束優(yōu)化。
?? ??? ?}
?? ? 5.改變一次最后一幀的位姿仿射是干啥。
?? ? 6.調用setAdjointsF函數(shù),這個函數(shù)是計算一些中間變量,為將相對值轉為絕對值做準備。
?? ? 7.調一次setPrecalcValues函數(shù),再調一次linearizeAll函數(shù),此時調linearizeAll是刪除一些不合理點帶著的殘差項
?? ? ? 下次再做窗口優(yōu)化的時候就不再用它們了。
}

理論部分主要是林突破和途金戈的博客。也貼個圖吧

?

?

途金戈的

?

/** * This file is part of DSO. * * Copyright 2016 Technical University of Munich and Intel. * Developed by Jakob Engel <engelj at in dot tum dot de>, * for more information see <http://vision.in.tum.de/dso>. * If you use this code, please cite the respective publications as * listed on the above website. * * DSO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DSO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DSO. If not, see <http://www.gnu.org/licenses/>. */#include "FullSystem/FullSystem.h"#include "stdio.h" #include "util/globalFuncs.h" #include <Eigen/LU> #include <algorithm> #include "IOWrapper/ImageDisplay.h" #include "util/globalCalib.h" #include <Eigen/SVD> #include <Eigen/Eigenvalues> #include "FullSystem/ResidualProjections.h"#include "OptimizationBackend/EnergyFunctional.h" #include "OptimizationBackend/EnergyFunctionalStructs.h"#include <cmath>#include <algorithm>namespace dso {void FullSystem::linearizeAll_Reductor(bool fixLinearization, std::vector<PointFrameResidual*>* toRemove, int min, int max, Vec10* stats, int tid) { //循環(huán)所有殘差項for(int k = min; k < max; k++){PointFrameResidual* r = activeResiduals[k];//在這里計算偏導數(shù) 填充雅克比矩陣用包括幾何雅克比圖像雅克比和//逆深度雅克比 ,還對點的state_NewState進行賦值//(*stats)[0]加的這個是殘差值(*stats)[0] += r->linearize(&Hcalib);if(fixLinearization){r->applyRes(true);if(r->efResidual->isActive()){if(r->isNew){PointHessian* p = r->point;//假設無限深度的投影點。Vec3f ptp_inf = r->host->targetPrecalc[r->target->idx].PRE_KRKiTll * Vec3f(p->u,p->v, 1); // projected point assuming infinite depth.//具有真實深度的投影點。Vec3f ptp = ptp_inf + r->host->targetPrecalc[r->target->idx].PRE_KtTll*p->idepth_scaled; // projected point with real depth.float relBS = 0.01*((ptp_inf.head<2>() / ptp_inf[2])-(ptp.head<2>() / ptp[2])).norm(); // 0.01 = one pixel.if(relBS > p->maxRelBaseline)p->maxRelBaseline = relBS;p->numGoodResiduals++;}}else{//壞點需要被剔除的toRemove[tid].push_back(activeResiduals[k]);}}} }void FullSystem::applyRes_Reductor(bool copyJacobians, int min, int max, Vec10* stats, int tid) {for(int k = min; k < max; k++)activeResiduals[k]->applyRes(true); } void FullSystem::setNewFrameEnergyTH() {// collect all residuals and make decision on TH.//收集所有殘差并對TH做出更新吧allResVec.clear();allResVec.reserve(activeResiduals.size() * 2);FrameHessian* newFrame = frameHessians.back();//最后一幀 //printf("=======id = %d\n",newFrame->idx);for(PointFrameResidual* r : activeResiduals)if(r->state_NewEnergyWithOutlier >= 0 && r->target == newFrame){allResVec.push_back(r->state_NewEnergyWithOutlier);//target為back的幀的所有成熟點的殘差}if(allResVec.size()==0){newFrame->frameEnergyTH = 12*12*patternNum;return; // should never happen, but lets make sure.} //printf("=======allResVec.size() = %d\n",allResVec.size());int nthIdx = setting_frameEnergyTHN*allResVec.size();//0.7assert(nthIdx < (int)allResVec.size());assert(setting_frameEnergyTHN < 1);std::nth_element(allResVec.begin(), allResVec.begin()+nthIdx, allResVec.end());float nthElement = sqrtf(allResVec[nthIdx]);newFrame->frameEnergyTH = nthElement*setting_frameEnergyTHFacMedian;newFrame->frameEnergyTH = 26.0f*setting_frameEnergyTHConstWeight + newFrame->frameEnergyTH*(1-setting_frameEnergyTHConstWeight);newFrame->frameEnergyTH = newFrame->frameEnergyTH*newFrame->frameEnergyTH;newFrame->frameEnergyTH *= setting_overallEnergyTHWeight*setting_overallEnergyTHWeight;}//相關導數(shù)計算,并且計算出殘差值來。 Vec3 FullSystem::linearizeAll(bool fixLinearization) {double lastEnergyP = 0;double lastEnergyR = 0;double num = 0;std::vector<PointFrameResidual*> toRemove[NUM_THREADS];for(int i = 0; i < NUM_THREADS; i++) toRemove[i].clear();if(multiThreading){treadReduce.reduce(boost::bind(&FullSystem::linearizeAll_Reductor, this, fixLinearization, toRemove, _1, _2, _3, _4), 0, activeResiduals.size(), 0);lastEnergyP = treadReduce.stats[0];}else{Vec10 stats;//雅克比矩陣元素:偏導數(shù)。還有點屬性都給賦個值linearizeAll_Reductor(fixLinearization, toRemove, 0, activeResiduals.size(),&stats,0); lastEnergyP = stats[0];} //修改閾值frameHessians.back()->frameEnergyTH的值就是修改 target幀的frameEnergyTH值setNewFrameEnergyTH();//這段是剔除優(yōu)化后為外點的殘差if(fixLinearization){for(PointFrameResidual* r : activeResiduals){PointHessian* ph = r->point;if(ph->lastResiduals[0].first == r)ph->lastResiduals[0].second = r->state_state;else if(ph->lastResiduals[1].first == r)ph->lastResiduals[1].second = r->state_state;}int nResRemoved=0;for(int i=0;i<NUM_THREADS;i++){//循環(huán)某個PointFrameResidual點for(PointFrameResidual* r : toRemove[i]){//取其PointHessian點PointHessian* ph = r->point;if(ph->lastResiduals[0].first == r)ph->lastResiduals[0].first=0;else if(ph->lastResiduals[1].first == r)ph->lastResiduals[1].first=0;//該點所有殘差項for(unsigned int k = 0; k < ph->residuals.size(); k++)if(ph->residuals[k] == r){ef->dropResidual(r->efResidual);deleteOut<PointFrameResidual>(ph->residuals,k);nResRemoved++;break;}}}}return Vec3(lastEnergyP, lastEnergyR, num); }// applies step to linearization point.將步驟應用于線性化點。 //優(yōu)化結果生效應該是修改各個待優(yōu)化參數(shù)值 //并通過評估本次增量的大小來判斷是否結束迭代 //待優(yōu)化參數(shù)包括N個逆深度 m*8+4的相機位姿 仿射 相機參數(shù) bool FullSystem::doStepFromBackup(float stepfacC,float stepfacT,float stepfacR,float stepfacA,float stepfacD) { // float meanStepC=0,meanStepP=0,meanStepD=0; // meanStepC += Hcalib.step.norm();//pstepfac 是預測的增量唄Vec10 pstepfac;//平移pstepfac.segment<3>(0).setConstant(stepfacT);//旋轉pstepfac.segment<3>(3).setConstant(stepfacR);//仿射pstepfac.segment<4>(6).setConstant(stepfacA);float sumA=0, sumB=0, sumT=0, sumR=0, sumID=0, numID=0;float sumNID=0;if(setting_solverMode & SOLVER_MOMENTUM){Hcalib.setValue(Hcalib.value_backup + Hcalib.step);//循環(huán)關鍵幀窗口for(FrameHessian* fh : frameHessians){Vec10 step0 = fh->step;step0.head<6>() += 0.5f*(fh->step_backup.head<6>());//修改fh->setState(fh->state_backup + step0);sumA += step0[6] * step0[6];sumB += step0[7] * step0[7];sumT += step0.segment<3>(0).squaredNorm();sumR += step0.segment<3>(3).squaredNorm();for(PointHessian* ph : fh->pointHessians){float stepx = ph->step+0.5f*(ph->step_backup);ph->setIdepth(ph->idepth_backup + stepx);sumID += stepx * stepx;sumNID += fabsf(ph->idepth_backup);numID++;ph->setIdepthZero(ph->idepth_backup + stepx);}}}else{//相機參數(shù)增量*權重 stepfacC 修改相機參數(shù)1 * 4//修改相機參數(shù)Hcalib.setValue(Hcalib.value_backup + stepfacC*Hcalib.step);//循環(huán)關鍵幀窗口for(FrameHessian* fh : frameHessians){// cwiseProduct 函數(shù)功能 R = P .* Q 對應點相乘//修改位姿仿射參數(shù)等 原有值+ 增量fh->setState(fh->state_backup + pstepfac.cwiseProduct(fh->step));sumA += fh->step[6]*fh->step[6];sumB += fh->step[7]*fh->step[7];sumT += fh->step.segment<3>(0).squaredNorm();sumR += fh->step.segment<3>(3).squaredNorm();//循環(huán)點修改逆深度值for(PointHessian* ph : fh->pointHessians){//修改逆深度值ph->setIdepth(ph->idepth_backup + stepfacD * ph->step);sumID += ph->step * ph->step;sumNID += fabsf(ph->idepth_backup);numID++;//修改idepth_zero值ph->setIdepthZero(ph->idepth_backup + stepfacD * ph->step);}}}sumA /= frameHessians.size();sumB /= frameHessians.size();sumR /= frameHessians.size();sumT /= frameHessians.size();sumID /= numID;sumNID /= numID;if(!setting_debugout_runquiet)printf("STEPS: A %.1f; B %.1f; R %.1f; T %.1f. \t",sqrtf(sumA) / (0.0005*setting_thOptIterations),sqrtf(sumB) / (0.00005*setting_thOptIterations),sqrtf(sumR) / (0.00005*setting_thOptIterations),sqrtf(sumT)*sumNID / (0.00005*setting_thOptIterations));EFDeltaValid=false;setPrecalcValues();return sqrtf(sumA) < 0.0005*setting_thOptIterations &&sqrtf(sumB) < 0.00005*setting_thOptIterations &&sqrtf(sumR) < 0.00005*setting_thOptIterations &&sqrtf(sumT)*sumNID < 0.00005*setting_thOptIterations; }// sets linearization point. //保留狀態(tài)有點逆深度idepth 相機參數(shù)Hcalib.value 位姿仿射fh->get_state() //以及它們對應的增量值 ph->step Hcalib.step fh->step void FullSystem::backupState(bool backupLastStep) {if(setting_solverMode & SOLVER_MOMENTUM){//非第一次迭代if(backupLastStep){Hcalib.step_backup = Hcalib.step;Hcalib.value_backup = Hcalib.value;for(FrameHessian* fh : frameHessians){fh->step_backup = fh->step;fh->state_backup = fh->get_state();for(PointHessian* ph : fh->pointHessians){ph->idepth_backup = ph->idepth;ph->step_backup = ph->step;}}}else//第一次迭代{Hcalib.step_backup.setZero();Hcalib.value_backup = Hcalib.value;//循環(huán)關鍵幀窗口for(FrameHessian* fh : frameHessians){fh->step_backup.setZero();fh->state_backup = fh->get_state();//循環(huán)成熟點for(PointHessian* ph : fh->pointHessians){ph->idepth_backup = ph->idepth;ph->step_backup=0;}}}}else{Hcalib.value_backup = Hcalib.value;for(FrameHessian* fh : frameHessians){fh->state_backup = fh->get_state();for(PointHessian* ph : fh->pointHessians)ph->idepth_backup = ph->idepth;}} }// sets linearization point. void FullSystem::loadSateBackup() {Hcalib.setValue(Hcalib.value_backup);for(FrameHessian* fh : frameHessians){fh->setState(fh->state_backup);for(PointHessian* ph : fh->pointHessians){ph->setIdepth(ph->idepth_backup);ph->setIdepthZero(ph->idepth_backup);}}EFDeltaValid=false;setPrecalcValues(); }double FullSystem::calcMEnergy() {if(setting_forceAceptStep) return 0;return ef->calcMEnergyF();}void FullSystem::printOptRes(const Vec3 &res, double resL, double resM, double resPrior, double LExact, float a, float b) {printf("A(%f)=(AV %.3f). Num: A(%'d) + M(%'d); ab %f %f!\n",res[0],sqrtf((float)(res[0] / (patternNum*ef->resInA))),ef->resInA,ef->resInM,a,b);}float FullSystem::optimize(int mnumOptIts) {if(frameHessians.size() < 2) return 0;if(frameHessians.size() < 3) mnumOptIts = 20;if(frameHessians.size() < 4) mnumOptIts = 15;// get statistics and active residuals.獲取統(tǒng)計數(shù)據(jù)和活動殘差。//清空活動點殘差隊列activeResiduals.clear();int numPoints = 0;//沒用int numLRes = 0;//沒用int galdg = 0;//循環(huán)窗口內(nèi)的幀for(FrameHessian* fh : frameHessians)for(PointHessian* ph : fh->pointHessians)//循環(huán)成熟點{//循環(huán)每個點在不同幀投影算的殘差for(PointFrameResidual* r : ph->residuals){//在外面舊成熟點相對新幀計算新殘差 isLinearized為false//在外面新激活成熟點相對非所在幀算新殘差 isLinearized為false//這些殘差點是累積下來的if(!r->efResidual->isLinearized){//加入活動點殘差隊列activeResiduals.push_back(r);//設置了幾個值r->resetOOB();//galdg ++;}elsenumLRes++;}//點總數(shù)numPoints++;}//相關導數(shù)計算Vec3 lastEnergy = linearizeAll(false);//這個函數(shù)返回值設置直接為0了double lastEnergyL = calcLEnergy();//這個函數(shù)返回值設置直接為0了double lastEnergyM = calcMEnergy();//在所有的 residual 中找到 isLinearized 為 false 的 residual,調用 //PointFrameResidual::applyRes(true),設置它們的 PointFrameResidual::ResState //(按照 FullSystem::optimizeImmaturePoint 的結果),如果是正常的 //點(ResState::IN)調用EFResidual::takeDataF()把 EFResidual::JpJdF 設置一下。 //這就算完成了優(yōu)化的準備工作。還計算了每個殘差的 //JPJDF值 是一個8*1的向量if(multiThreading)treadReduce.reduce(boost::bind(&FullSystem::applyRes_Reductor, this, true, _1, _2, _3, _4), 0, activeResiduals.size(), 50);else{//計算了下博客中的4.7.6提到的中間變量 applyRes_Reductor(true, 0, activeResiduals.size(), 0, 0);}if(!setting_debugout_runquiet){printf("Initial Error \t");printOptRes(lastEnergy, lastEnergyL, lastEnergyM, 0, 0, frameHessians.back()->aff_g2l().a, frameHessians.back()->aff_g2l().b);} //調試繪圖跟蹤debugPlotTracking();double lambda = 1e-1;//0.1float stepsize = 1;VecX previousX = VecX::Constant(CPARS + 8 * frameHessians.size(), NAN);//開始迭代優(yōu)化for(int iteration = 0; iteration < mnumOptIts; iteration++){// solve!//保存當前的狀態(tài),這是為了在優(yōu)化結果不好的情況下可以回退backupState(iteration!=0);//solveSystemNew(0);//求解優(yōu)化增量方程 解出的結果有68包含的各項的小增量,所有點深度值//的小增量。都是絕對增量值切記切記solveSystem(iteration, lambda);double incDirChange = (1e-20 + previousX.dot(ef->lastX)) / (1e-20 + previousX.norm() * ef->lastX.norm());previousX = ef->lastX;if(std::isfinite(incDirChange) && (setting_solverMode & SOLVER_STEPMOMENTUM)){float newStepsize = exp(incDirChange * 1.4);if(incDirChange < 0 && stepsize>1) stepsize = 1;stepsize = sqrtf(sqrtf(newStepsize * stepsize * stepsize * stepsize));if(stepsize > 2) stepsize=2;if(stepsize <0.25) stepsize=0.25;} //優(yōu)化結果生效應該是修改各個待優(yōu)化參數(shù)值 //并通過評估本次增量的大小來判斷是否結束迭代 //待優(yōu)化參數(shù)包括M個點的逆深度 m * 8 + 4的相機位姿 仿射 相機參數(shù)bool canbreak = doStepFromBackup(stepsize, stepsize, stepsize, stepsize, stepsize);// eval new energy!評估新能量//用上面修改的新數(shù)據(jù)計算新的能量值newEnergy,并且重新計算一組//相關導數(shù)Vec3 newEnergy = linearizeAll(false);double newEnergyL = calcLEnergy();//返回0 不用去費腦子了double newEnergyM = calcMEnergy();//返回0不用去費腦子了if(!setting_debugout_runquiet){printf("%s %d (L %.2f, dir %.2f, ss %.1f): \t",(newEnergy[0] + newEnergy[1] + newEnergyL + newEnergyM <lastEnergy[0] + lastEnergy[1] + lastEnergyL + lastEnergyM) ? "ACCEPT" : "REJECT",iteration,log10(lambda),incDirChange,stepsize);printOptRes(newEnergy, newEnergyL, newEnergyM , 0, 0, frameHessians.back()->aff_g2l().a, frameHessians.back()->aff_g2l().b);}if(setting_forceAceptStep || (newEnergy[0] + newEnergy[1] + newEnergyL + newEnergyM <lastEnergy[0] + lastEnergy[1] + lastEnergyL + lastEnergyM)){if(multiThreading)treadReduce.reduce(boost::bind(&FullSystem::applyRes_Reductor, this, true, _1, _2, _3, _4), 0, activeResiduals.size(), 50);else{//中間變量計算applyRes_Reductor(true,0,activeResiduals.size(),0,0);}lastEnergy = newEnergy;lastEnergyL = newEnergyL;lastEnergyM = newEnergyM;lambda *= 0.25;}else{//能量升高了就使用 FullSystem::loadSateBackup() 將結果回滾。loadSateBackup();//重新算一次lastEnergy = linearizeAll(false);lastEnergyL = calcLEnergy();lastEnergyM = calcMEnergy();lambda *= 1e2;}if(canbreak && iteration >= setting_minOptIterations) break;}Vec10 newStateZero = Vec10::Zero();newStateZero.segment<2>(6) = frameHessians.back()->get_state().segment<2>(6);//setStateZero賦值的地方 用newStateZero賦值frameHessians.back()->setEvalPT(frameHessians.back()->PRE_worldToCam, newStateZero);EFDeltaValid = false;EFAdjointsValid = false;ef->setAdjointsF(&Hcalib);setPrecalcValues();//在跳出循環(huán)體之后調用一次 FullSystem::linearizeAll(true), //效果是將優(yōu)化之后成為 outlier 的 residual 剔除,剩下 //正常的 residual 調用一次 EFResidual::takeDataF() 計算新的 //EFResidual::JpJdF (這里涉及到 FEJ)。注意一下 lastEnergy = linearizeAll(true);if(!std::isfinite((double)lastEnergy[0]) || !std::isfinite((double)lastEnergy[1]) || !std::isfinite((double)lastEnergy[2])){printf("KF Tracking failed: LOST!\n");isLost=true;}statistics_lastFineTrackRMSE = sqrtf((float)(lastEnergy[0] / (patternNum*ef->resInA)));if(calibLog != 0){(*calibLog) << Hcalib.value_scaled.transpose() <<" " << frameHessians.back()->get_state_scaled().transpose() <<" " << sqrtf((float)(lastEnergy[0] / (patternNum*ef->resInA))) <<" " << ef->resInM << "\n";calibLog->flush();}//最終在這要更新關鍵幀的位姿和仿射參數(shù) 。用優(yōu)化后的值更新。{boost::unique_lock<boost::mutex> crlock(shellPoseMutex);//循環(huán)關鍵幀窗口for(FrameHessian* fh : frameHessians){fh->shell->camToWorld = fh->PRE_camToWorld;fh->shell->aff_g2l = fh->aff_g2l();}}debugPlotTracking();//返回的這個值是點的平均殘差值的開方return sqrtf((float)(lastEnergy[0] / (patternNum * ef->resInA)));}void FullSystem::solveSystem(int iteration, double lambda) { //零空間給lastNullspaces_pose他們幾個賦值呢,affA affB壓根沒用到 不用去理會ef->lastNullspaces_forLogging = getNullspaces(ef->lastNullspaces_pose,ef->lastNullspaces_scale,ef->lastNullspaces_affA,ef->lastNullspaces_affB); //解方程的主函數(shù)ef->solveSystemF(iteration, lambda,&Hcalib); }double FullSystem::calcLEnergy() {if(setting_forceAceptStep) return 0;double Ef = ef->calcLEnergyF_MT();return Ef;}void FullSystem::removeOutliers() {int numPointsDropped=0;for(FrameHessian* fh : frameHessians){for(unsigned int i=0;i<fh->pointHessians.size();i++){PointHessian* ph = fh->pointHessians[i];if(ph==0) continue;if(ph->residuals.size() == 0){fh->pointHessiansOut.push_back(ph);ph->efPoint->stateFlag = EFPointStatus::PS_DROP;fh->pointHessians[i] = fh->pointHessians.back();fh->pointHessians.pop_back();i--;numPointsDropped++;}}}ef->dropPointsF(); }std::vector<VecX> FullSystem::getNullspaces(std::vector<VecX> &nullspaces_pose1,std::vector<VecX> &nullspaces_scale1,std::vector<VecX> &nullspaces_affA,std::vector<VecX> &nullspaces_affB) { // 先做個清空nullspaces_pose1.clear();nullspaces_scale1.clear();nullspaces_affA.clear();nullspaces_affB.clear();int n = CPARS + frameHessians.size() * 8;std::vector<VecX> nullspaces_x0_pre;for(int i = 0; i < 6; i++){VecX nullspace_x0(n);nullspace_x0.setZero();for(FrameHessian* fh : frameHessians){nullspace_x0.segment<6>(CPARS+fh->idx * 8) = fh->nullspaces_pose.col(i);nullspace_x0.segment<3>(CPARS+fh->idx * 8) *= SCALE_XI_TRANS_INVERSE;nullspace_x0.segment<3>(CPARS+fh->idx * 8 + 3) *= SCALE_XI_ROT_INVERSE;}nullspaces_x0_pre.push_back(nullspace_x0);nullspaces_pose1.push_back(nullspace_x0);}for(int i=0;i<2;i++){VecX nullspace_x0(n);nullspace_x0.setZero();for(FrameHessian* fh : frameHessians){nullspace_x0.segment<2>(CPARS+fh->idx*8+6) = fh->nullspaces_affine.col(i).head<2>();nullspace_x0[CPARS+fh->idx*8+6] *= SCALE_A_INVERSE;nullspace_x0[CPARS+fh->idx*8+7] *= SCALE_B_INVERSE;}nullspaces_x0_pre.push_back(nullspace_x0);if(i==0) nullspaces_affA.push_back(nullspace_x0);if(i==1) nullspaces_affB.push_back(nullspace_x0);}VecX nullspace_x0(n);nullspace_x0.setZero();for(FrameHessian* fh : frameHessians){nullspace_x0.segment<6>(CPARS+fh->idx*8) = fh->nullspaces_scale;nullspace_x0.segment<3>(CPARS+fh->idx*8) *= SCALE_XI_TRANS_INVERSE;nullspace_x0.segment<3>(CPARS+fh->idx*8+3) *= SCALE_XI_ROT_INVERSE;}nullspaces_x0_pre.push_back(nullspace_x0);nullspaces_scale1.push_back(nullspace_x0);return nullspaces_x0_pre; }} /** * This file is part of DSO. * * Copyright 2016 Technical University of Munich and Intel. * Developed by Jakob Engel <engelj at in dot tum dot de>, * for more information see <http://vision.in.tum.de/dso>. * If you use this code, please cite the respective publications as * listed on the above website. * * DSO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DSO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DSO. If not, see <http://www.gnu.org/licenses/>. *//** KFBuffer.cpp** Created on: Jan 7, 2014* Author: engelj*/#include "FullSystem/FullSystem.h"#include "stdio.h" #include "util/globalFuncs.h" #include <Eigen/LU> #include <algorithm> #include "IOWrapper/ImageDisplay.h" #include "util/globalCalib.h" #include <Eigen/SVD> #include <Eigen/Eigenvalues>#include "FullSystem/ResidualProjections.h" #include "OptimizationBackend/EnergyFunctional.h" #include "OptimizationBackend/EnergyFunctionalStructs.h"#include "FullSystem/HessianBlocks.h"namespace dso { int PointFrameResidual::instanceCounter = 0;long runningResID=0;PointFrameResidual::PointFrameResidual(){assert(false); instanceCounter++;}PointFrameResidual::~PointFrameResidual(){assert(efResidual==0); instanceCounter--; delete J;}PointFrameResidual::PointFrameResidual(PointHessian* point_, FrameHessian* host_, FrameHessian* target_) :point(point_),host(host_),target(target_) {efResidual=0;instanceCounter++;resetOOB();J = new RawResidualJacobian();assert(((long)J)%16==0);isNew=true; }//投影點關于各個參數(shù)的導數(shù)。其組成雅克比矩陣 double PointFrameResidual::linearize(CalibHessian* HCalib) {state_NewEnergyWithOutlier = -1;if(state_state == ResState::OOB){ state_NewState = ResState::OOB; return state_energy; }FrameFramePrecalc* precalc = &(host->targetPrecalc[target->idx]);float energyLeft=0;const Eigen::Vector3f* dIl = target->dI;//const float* const Il = target->I;const Mat33f &PRE_KRKiTll = precalc->PRE_KRKiTll;const Vec3f &PRE_KtTll = precalc->PRE_KtTll;const Mat33f &PRE_RTll_0x = precalc->PRE_RTll_0;const Vec3f &PRE_tTll_0 = precalc->PRE_tTll_0;const float * const color = point->color;const float * const weights = point->weights;Vec2f affLL = precalc->PRE_aff_mode;float b0 = precalc->PRE_b0_mode;Vec6f d_xi_x, d_xi_y;Vec4f d_C_x, d_C_y;float d_d_x, d_d_y;{float drescale, u, v, new_idepth;float Ku, Kv;Vec3f KliP; //點越界直接返回if(!projectPoint(point->u, point->v, point->idepth_zero_scaled, 0, 0,HCalib,PRE_RTll_0x,PRE_tTll_0, drescale, u, v, Ku, Kv, KliP, new_idepth)){ state_NewState = ResState::OOB; return state_energy; }centerProjectedTo = Vec3f(Ku, Kv, new_idepth);// diff d_idepth//target幀點坐標對逆深度求偏導d_d_x = drescale * (PRE_tTll_0[0] - PRE_tTll_0[2]*u)*SCALE_IDEPTH*HCalib->fxl();d_d_y = drescale * (PRE_tTll_0[1] - PRE_tTll_0[2]*v)*SCALE_IDEPTH*HCalib->fyl();// diff calib//target幀點坐標對相機參數(shù)求偏導d_C_x[2] = drescale*(PRE_RTll_0x(2,0)*u-PRE_RTll_0x(0,0));d_C_x[3] = HCalib->fxl() * drescale*(PRE_RTll_0x(2,1)*u-PRE_RTll_0x(0,1)) * HCalib->fyli();d_C_x[0] = KliP[0]*d_C_x[2];d_C_x[1] = KliP[1]*d_C_x[3];d_C_y[2] = HCalib->fyl() * drescale*(PRE_RTll_0x(2,0)*v-PRE_RTll_0x(1,0)) * HCalib->fxli();d_C_y[3] = drescale*(PRE_RTll_0x(2,1)*v-PRE_RTll_0x(1,1));d_C_y[0] = KliP[0]*d_C_y[2];d_C_y[1] = KliP[1]*d_C_y[3];d_C_x[0] = (d_C_x[0]+u)*SCALE_F;d_C_x[1] *= SCALE_F;d_C_x[2] = (d_C_x[2]+1)*SCALE_C;d_C_x[3] *= SCALE_C;d_C_y[0] *= SCALE_F;d_C_y[1] = (d_C_y[1]+v)*SCALE_F;d_C_y[2] *= SCALE_C;d_C_y[3] = (d_C_y[3]+1)*SCALE_C;// target幀點坐標對位姿增量求偏導 DSO追蹤與優(yōu)化公式56d_xi_x[0] = new_idepth*HCalib->fxl();//對應論文公式13 dso詳解博客公式d_xi_x[1] = 0;d_xi_x[2] = -new_idepth*u*HCalib->fxl();d_xi_x[3] = -u*v*HCalib->fxl();d_xi_x[4] = (1+u*u)*HCalib->fxl();d_xi_x[5] = -v*HCalib->fxl();d_xi_y[0] = 0;d_xi_y[1] = new_idepth*HCalib->fyl();d_xi_y[2] = -new_idepth*v*HCalib->fyl();d_xi_y[3] = -(1+v*v)*HCalib->fyl();d_xi_y[4] = u*v*HCalib->fyl();d_xi_y[5] = u*HCalib->fyl();}{//位姿參數(shù)雅克比矩陣 =====>坐標對位姿求偏導J->Jpdxi[0] = d_xi_x;J->Jpdxi[1] = d_xi_y;//相機參數(shù)雅克比矩陣 =====>坐標對相機參數(shù)求偏導J->Jpdc[0] = d_C_x;J->Jpdc[1] = d_C_y;//逆深度雅克比矩陣 =====>坐標對逆深度求偏導J->Jpdd[0] = d_d_x;J->Jpdd[1] = d_d_y;}float JIdxJIdx_00=0, JIdxJIdx_11=0, JIdxJIdx_10=0;float JabJIdx_00=0, JabJIdx_01=0, JabJIdx_10=0, JabJIdx_11=0;float JabJab_00=0, JabJab_01=0, JabJab_11=0;float wJI2_sum = 0; //圖像坐標的偏導數(shù) 以及光度仿射變換的偏導,是對8個點求 //是像素坐標關于梯度增量 光度增量等的偏導for(int idx = 0; idx < patternNum; idx++){float Ku, Kv;if(!projectPoint(point->u+patternP[idx][0], point->v+patternP[idx][1], point->idepth_scaled, PRE_KRKiTll, PRE_KtTll, Ku, Kv)){ state_NewState = ResState::OOB; return state_energy; }projectedTo[idx][0] = Ku;projectedTo[idx][1] = Kv;Vec3f hitColor = (getInterpolatedElement33(dIl, Ku, Kv, wG[0]));float residual = hitColor[0] - (float)(affLL[0] * color[idx] + affLL[1]); //點坐標對光度變化增量求偏導float drdA = (color[idx] - b0);if(!std::isfinite((float)hitColor[0])){ state_NewState = ResState::OOB; return state_energy; }float w = sqrtf(setting_outlierTHSumComponent / (setting_outlierTHSumComponent + hitColor.tail<2>().squaredNorm()));w = 0.5f * (w + weights[idx]);float hw = fabsf(residual) < setting_huberTH ? 1 : setting_huberTH / fabsf(residual);//hub范數(shù)energyLeft += w * w * hw * residual * residual * (2 - hw);{if(hw < 1) hw = sqrtf(hw);hw = hw*w;hitColor[1]*=hw;hitColor[2]*=hw;J->resF[idx] = residual*hw;//殘差對圖像坐標求偏導J->JIdx[0][idx] = hitColor[1];J->JIdx[1][idx] = hitColor[2];//殘差對仿射求偏導J->JabF[0][idx] = drdA*hw;J->JabF[1][idx] = hw;JIdxJIdx_00+=hitColor[1]*hitColor[1];JIdxJIdx_11+=hitColor[2]*hitColor[2];JIdxJIdx_10+=hitColor[1]*hitColor[2];//轉置計算體現(xiàn)在這 +表示的ΣJabJIdx_00+= drdA*hw * hitColor[1];JabJIdx_01+= drdA*hw* hitColor[2];JabJIdx_10+= hw * hitColor[1];JabJIdx_11+= hw * hitColor[2];JabJab_00+= drdA*hw*drdA*hw;JabJab_01+= drdA*hw*hw;JabJab_11+= hw*hw;wJI2_sum += hw*hw*(hitColor[1]*hitColor[1] + hitColor[2]*hitColor[2]);if(setting_affineOptModeA < 0) J->JabF[0][idx]=0;if(setting_affineOptModeB < 0) J->JabF[1][idx]=0;}} //(殘差 /像素坐標)轉置*(殘差 /像素坐標)J->JIdx2(0,0) = JIdxJIdx_00;J->JIdx2(0,1) = JIdxJIdx_10;J->JIdx2(1,0) = JIdxJIdx_10;J->JIdx2(1,1) = JIdxJIdx_11;//(殘差 /光度參數(shù))轉置*(殘差 /像素坐標)J->JabJIdx(0,0) = JabJIdx_00;J->JabJIdx(0,1) = JabJIdx_01;J->JabJIdx(1,0) = JabJIdx_10;J->JabJIdx(1,1) = JabJIdx_11;//(殘差 /光度參數(shù))轉置*(殘差 /光度參數(shù))J->Jab2(0,0) = JabJab_00;J->Jab2(0,1) = JabJab_01;J->Jab2(1,0) = JabJab_01;J->Jab2(1,1) = JabJab_11;state_NewEnergyWithOutlier = energyLeft;if(energyLeft > std::max<float>(host->frameEnergyTH, target->frameEnergyTH) || wJI2_sum < 2){energyLeft = std::max<float>(host->frameEnergyTH, target->frameEnergyTH);//異常點state_NewState = ResState::OUTLIER;}else{//正常點state_NewState = ResState::IN;}state_NewEnergy = energyLeft;//返回值是殘差值return energyLeft; }void PointFrameResidual::debugPlot() {if(state_state==ResState::OOB) return;Vec3b cT = Vec3b(0,0,0);if(freeDebugParam5==0){float rT = 20*sqrt(state_energy/9);if(rT<0) rT=0; if(rT>255)rT=255;cT = Vec3b(0,255-rT,rT);}else{if(state_state == ResState::IN) cT = Vec3b(255,0,0);else if(state_state == ResState::OOB) cT = Vec3b(255,255,0);else if(state_state == ResState::OUTLIER) cT = Vec3b(0,0,255);else cT = Vec3b(255,255,255);}for(int i=0;i<patternNum;i++){if((projectedTo[i][0] > 2 && projectedTo[i][1] > 2 && projectedTo[i][0] < wG[0]-3 && projectedTo[i][1] < hG[0]-3 ))target->debugImage->setPixel1((float)projectedTo[i][0], (float)projectedTo[i][1],cT);} }//設置它們的 PointFrameResidual::ResState ( //按照 FullSystem::optimizeImmaturePoint 的結果) //,如果是正常的點(ResState::IN)調用 //EFResidual::takeDataF()把 EFResidual::JpJdF 設置 //一下。這就算完成了優(yōu)化的準備工作。 // 計算每個殘差的JPJDF值 void PointFrameResidual::applyRes(bool copyJacobians) {if(copyJacobians){if(state_state == ResState::OOB){assert(!efResidual->isActiveAndIsGoodNEW);return; // can never go back from OOB}if(state_NewState == ResState::IN)// && ){efResidual->isActiveAndIsGoodNEW=true;efResidual->takeDataF();}else{efResidual->isActiveAndIsGoodNEW=false;}}setState(state_NewState);state_energy = state_NewEnergy; } } /** * This file is part of DSO. * * Copyright 2016 Technical University of Munich and Intel. * Developed by Jakob Engel <engelj at in dot tum dot de>, * for more information see <http://vision.in.tum.de/dso>. * If you use this code, please cite the respective publications as * listed on the above website. * * DSO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DSO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DSO. If not, see <http://www.gnu.org/licenses/>. */#include "FullSystem/FullSystem.h"#include "stdio.h" #include "util/globalFuncs.h" #include <Eigen/LU> #include <algorithm> #include "IOWrapper/ImageDisplay.h" #include "util/globalCalib.h" #include <Eigen/SVD> #include <Eigen/Eigenvalues> #include "FullSystem/ResidualProjections.h"#include "OptimizationBackend/EnergyFunctional.h" #include "OptimizationBackend/EnergyFunctionalStructs.h"#include <cmath>#include <algorithm>namespace dso {void FullSystem::linearizeAll_Reductor(bool fixLinearization, std::vector<PointFrameResidual*>* toRemove, int min, int max, Vec10* stats, int tid) { //循環(huán)所有殘差項for(int k = min; k < max; k++){PointFrameResidual* r = activeResiduals[k];//在這里計算偏導數(shù) 填充雅克比矩陣用包括幾何雅克比圖像雅克比和//逆深度雅克比 ,還對點的state_NewState進行賦值//(*stats)[0]加的這個是殘差值(*stats)[0] += r->linearize(&Hcalib);if(fixLinearization){r->applyRes(true);if(r->efResidual->isActive()){if(r->isNew){PointHessian* p = r->point;//假設無限深度的投影點。Vec3f ptp_inf = r->host->targetPrecalc[r->target->idx].PRE_KRKiTll * Vec3f(p->u,p->v, 1); // projected point assuming infinite depth.//具有真實深度的投影點。Vec3f ptp = ptp_inf + r->host->targetPrecalc[r->target->idx].PRE_KtTll*p->idepth_scaled; // projected point with real depth.float relBS = 0.01*((ptp_inf.head<2>() / ptp_inf[2])-(ptp.head<2>() / ptp[2])).norm(); // 0.01 = one pixel.if(relBS > p->maxRelBaseline)p->maxRelBaseline = relBS;p->numGoodResiduals++;}}else{//壞點需要被剔除的toRemove[tid].push_back(activeResiduals[k]);}}} }void FullSystem::applyRes_Reductor(bool copyJacobians, int min, int max, Vec10* stats, int tid) {for(int k = min; k < max; k++)activeResiduals[k]->applyRes(true); } void FullSystem::setNewFrameEnergyTH() {// collect all residuals and make decision on TH.//收集所有殘差并對TH做出更新吧allResVec.clear();allResVec.reserve(activeResiduals.size() * 2);FrameHessian* newFrame = frameHessians.back();//最后一幀 //printf("=======id = %d\n",newFrame->idx);for(PointFrameResidual* r : activeResiduals)if(r->state_NewEnergyWithOutlier >= 0 && r->target == newFrame){allResVec.push_back(r->state_NewEnergyWithOutlier);//target為back的幀的所有成熟點的殘差}if(allResVec.size()==0){newFrame->frameEnergyTH = 12*12*patternNum;return; // should never happen, but lets make sure.} //printf("=======allResVec.size() = %d\n",allResVec.size());int nthIdx = setting_frameEnergyTHN*allResVec.size();//0.7assert(nthIdx < (int)allResVec.size());assert(setting_frameEnergyTHN < 1);std::nth_element(allResVec.begin(), allResVec.begin()+nthIdx, allResVec.end());float nthElement = sqrtf(allResVec[nthIdx]);newFrame->frameEnergyTH = nthElement*setting_frameEnergyTHFacMedian;newFrame->frameEnergyTH = 26.0f*setting_frameEnergyTHConstWeight + newFrame->frameEnergyTH*(1-setting_frameEnergyTHConstWeight);newFrame->frameEnergyTH = newFrame->frameEnergyTH*newFrame->frameEnergyTH;newFrame->frameEnergyTH *= setting_overallEnergyTHWeight*setting_overallEnergyTHWeight;}//相關導數(shù)計算,并且計算出殘差值來。 Vec3 FullSystem::linearizeAll(bool fixLinearization) {double lastEnergyP = 0;double lastEnergyR = 0;double num = 0;std::vector<PointFrameResidual*> toRemove[NUM_THREADS];for(int i = 0; i < NUM_THREADS; i++) toRemove[i].clear();if(multiThreading){treadReduce.reduce(boost::bind(&FullSystem::linearizeAll_Reductor, this, fixLinearization, toRemove, _1, _2, _3, _4), 0, activeResiduals.size(), 0);lastEnergyP = treadReduce.stats[0];}else{Vec10 stats;//雅克比矩陣元素:偏導數(shù)。還有點屬性都給賦個值linearizeAll_Reductor(fixLinearization, toRemove, 0, activeResiduals.size(),&stats,0); lastEnergyP = stats[0];} //修改閾值frameHessians.back()->frameEnergyTH的值就是修改 target幀的frameEnergyTH值setNewFrameEnergyTH();//這段是剔除優(yōu)化后為外點的殘差if(fixLinearization){for(PointFrameResidual* r : activeResiduals){PointHessian* ph = r->point;if(ph->lastResiduals[0].first == r)ph->lastResiduals[0].second = r->state_state;else if(ph->lastResiduals[1].first == r)ph->lastResiduals[1].second = r->state_state;}int nResRemoved=0;for(int i=0;i<NUM_THREADS;i++){//循環(huán)某個PointFrameResidual點for(PointFrameResidual* r : toRemove[i]){//取其PointHessian點PointHessian* ph = r->point;if(ph->lastResiduals[0].first == r)ph->lastResiduals[0].first=0;else if(ph->lastResiduals[1].first == r)ph->lastResiduals[1].first=0;//該點所有殘差項for(unsigned int k = 0; k < ph->residuals.size(); k++)if(ph->residuals[k] == r){ef->dropResidual(r->efResidual);deleteOut<PointFrameResidual>(ph->residuals,k);nResRemoved++;break;}}}}return Vec3(lastEnergyP, lastEnergyR, num); }// applies step to linearization point.將步驟應用于線性化點。 //優(yōu)化結果生效應該是修改各個待優(yōu)化參數(shù)值 //并通過評估本次增量的大小來判斷是否結束迭代 //待優(yōu)化參數(shù)包括N個逆深度 m*8+4的相機位姿 仿射 相機參數(shù) bool FullSystem::doStepFromBackup(float stepfacC,float stepfacT,float stepfacR,float stepfacA,float stepfacD) { // float meanStepC=0,meanStepP=0,meanStepD=0; // meanStepC += Hcalib.step.norm();//pstepfac 是預測的增量唄Vec10 pstepfac;//平移pstepfac.segment<3>(0).setConstant(stepfacT);//旋轉pstepfac.segment<3>(3).setConstant(stepfacR);//仿射pstepfac.segment<4>(6).setConstant(stepfacA);float sumA=0, sumB=0, sumT=0, sumR=0, sumID=0, numID=0;float sumNID=0;if(setting_solverMode & SOLVER_MOMENTUM){Hcalib.setValue(Hcalib.value_backup + Hcalib.step);//循環(huán)關鍵幀窗口for(FrameHessian* fh : frameHessians){Vec10 step0 = fh->step;step0.head<6>() += 0.5f*(fh->step_backup.head<6>());//修改fh->setState(fh->state_backup + step0);sumA += step0[6] * step0[6];sumB += step0[7] * step0[7];sumT += step0.segment<3>(0).squaredNorm();sumR += step0.segment<3>(3).squaredNorm();for(PointHessian* ph : fh->pointHessians){float stepx = ph->step+0.5f*(ph->step_backup);ph->setIdepth(ph->idepth_backup + stepx);sumID += stepx * stepx;sumNID += fabsf(ph->idepth_backup);numID++;ph->setIdepthZero(ph->idepth_backup + stepx);}}}else{//相機參數(shù)增量*權重 stepfacC 修改相機參數(shù)1 * 4//修改相機參數(shù)Hcalib.setValue(Hcalib.value_backup + stepfacC*Hcalib.step);//循環(huán)關鍵幀窗口for(FrameHessian* fh : frameHessians){// cwiseProduct 函數(shù)功能 R = P .* Q 對應點相乘//修改位姿仿射參數(shù)等 原有值+ 增量fh->setState(fh->state_backup + pstepfac.cwiseProduct(fh->step));sumA += fh->step[6]*fh->step[6];sumB += fh->step[7]*fh->step[7];sumT += fh->step.segment<3>(0).squaredNorm();sumR += fh->step.segment<3>(3).squaredNorm();//循環(huán)點修改逆深度值for(PointHessian* ph : fh->pointHessians){//修改逆深度值ph->setIdepth(ph->idepth_backup + stepfacD * ph->step);sumID += ph->step * ph->step;sumNID += fabsf(ph->idepth_backup);numID++;//修改idepth_zero值ph->setIdepthZero(ph->idepth_backup + stepfacD * ph->step);}}}sumA /= frameHessians.size();sumB /= frameHessians.size();sumR /= frameHessians.size();sumT /= frameHessians.size();sumID /= numID;sumNID /= numID;if(!setting_debugout_runquiet)printf("STEPS: A %.1f; B %.1f; R %.1f; T %.1f. \t",sqrtf(sumA) / (0.0005*setting_thOptIterations),sqrtf(sumB) / (0.00005*setting_thOptIterations),sqrtf(sumR) / (0.00005*setting_thOptIterations),sqrtf(sumT)*sumNID / (0.00005*setting_thOptIterations));EFDeltaValid=false;setPrecalcValues();return sqrtf(sumA) < 0.0005*setting_thOptIterations &&sqrtf(sumB) < 0.00005*setting_thOptIterations &&sqrtf(sumR) < 0.00005*setting_thOptIterations &&sqrtf(sumT)*sumNID < 0.00005*setting_thOptIterations; }// sets linearization point. //保留狀態(tài)有點逆深度idepth 相機參數(shù)Hcalib.value 位姿仿射fh->get_state() //以及它們對應的增量值 ph->step Hcalib.step fh->step void FullSystem::backupState(bool backupLastStep) {if(setting_solverMode & SOLVER_MOMENTUM){//非第一次迭代if(backupLastStep){Hcalib.step_backup = Hcalib.step;Hcalib.value_backup = Hcalib.value;for(FrameHessian* fh : frameHessians){fh->step_backup = fh->step;fh->state_backup = fh->get_state();for(PointHessian* ph : fh->pointHessians){ph->idepth_backup = ph->idepth;ph->step_backup = ph->step;}}}else//第一次迭代{Hcalib.step_backup.setZero();Hcalib.value_backup = Hcalib.value;//循環(huán)關鍵幀窗口for(FrameHessian* fh : frameHessians){fh->step_backup.setZero();fh->state_backup = fh->get_state();//循環(huán)成熟點for(PointHessian* ph : fh->pointHessians){ph->idepth_backup = ph->idepth;ph->step_backup=0;}}}}else{Hcalib.value_backup = Hcalib.value;for(FrameHessian* fh : frameHessians){fh->state_backup = fh->get_state();for(PointHessian* ph : fh->pointHessians)ph->idepth_backup = ph->idepth;}} }// sets linearization point. void FullSystem::loadSateBackup() {Hcalib.setValue(Hcalib.value_backup);for(FrameHessian* fh : frameHessians){fh->setState(fh->state_backup);for(PointHessian* ph : fh->pointHessians){ph->setIdepth(ph->idepth_backup);ph->setIdepthZero(ph->idepth_backup);}}EFDeltaValid=false;setPrecalcValues(); }double FullSystem::calcMEnergy() {if(setting_forceAceptStep) return 0;return ef->calcMEnergyF();}void FullSystem::printOptRes(const Vec3 &res, double resL, double resM, double resPrior, double LExact, float a, float b) {printf("A(%f)=(AV %.3f). Num: A(%'d) + M(%'d); ab %f %f!\n",res[0],sqrtf((float)(res[0] / (patternNum*ef->resInA))),ef->resInA,ef->resInM,a,b);}float FullSystem::optimize(int mnumOptIts) {if(frameHessians.size() < 2) return 0;if(frameHessians.size() < 3) mnumOptIts = 20;if(frameHessians.size() < 4) mnumOptIts = 15;// get statistics and active residuals.獲取統(tǒng)計數(shù)據(jù)和活動殘差。//清空活動點殘差隊列activeResiduals.clear();int numPoints = 0;//沒用int numLRes = 0;//沒用int galdg = 0;//循環(huán)窗口內(nèi)的幀for(FrameHessian* fh : frameHessians)for(PointHessian* ph : fh->pointHessians)//循環(huán)成熟點{//循環(huán)每個點在不同幀投影算的殘差for(PointFrameResidual* r : ph->residuals){//在外面舊成熟點相對新幀計算新殘差 isLinearized為false//在外面新激活成熟點相對非所在幀算新殘差 isLinearized為false//這些殘差點是累積下來的if(!r->efResidual->isLinearized){//加入活動點殘差隊列activeResiduals.push_back(r);//設置了幾個值r->resetOOB();//galdg ++;}elsenumLRes++;}//點總數(shù)numPoints++;}//相關導數(shù)計算Vec3 lastEnergy = linearizeAll(false);//這個函數(shù)返回值設置直接為0了double lastEnergyL = calcLEnergy();//這個函數(shù)返回值設置直接為0了double lastEnergyM = calcMEnergy();//在所有的 residual 中找到 isLinearized 為 false 的 residual,調用 //PointFrameResidual::applyRes(true),設置它們的 PointFrameResidual::ResState //(按照 FullSystem::optimizeImmaturePoint 的結果),如果是正常的 //點(ResState::IN)調用EFResidual::takeDataF()把 EFResidual::JpJdF 設置一下。 //這就算完成了優(yōu)化的準備工作。還計算了每個殘差的 //JPJDF值 是一個8*1的向量if(multiThreading)treadReduce.reduce(boost::bind(&FullSystem::applyRes_Reductor, this, true, _1, _2, _3, _4), 0, activeResiduals.size(), 50);else{//計算了下博客中的4.7.6提到的中間變量 applyRes_Reductor(true, 0, activeResiduals.size(), 0, 0);}if(!setting_debugout_runquiet){printf("Initial Error \t");printOptRes(lastEnergy, lastEnergyL, lastEnergyM, 0, 0, frameHessians.back()->aff_g2l().a, frameHessians.back()->aff_g2l().b);} //調試繪圖跟蹤debugPlotTracking();double lambda = 1e-1;//0.1float stepsize = 1;VecX previousX = VecX::Constant(CPARS + 8 * frameHessians.size(), NAN);//開始迭代優(yōu)化for(int iteration = 0; iteration < mnumOptIts; iteration++){// solve!//保存當前的狀態(tài),這是為了在優(yōu)化結果不好的情況下可以回退backupState(iteration!=0);//solveSystemNew(0);//求解優(yōu)化增量方程 解出的結果有68包含的各項的小增量,所有點深度值//的小增量。都是絕對增量值切記切記solveSystem(iteration, lambda);double incDirChange = (1e-20 + previousX.dot(ef->lastX)) / (1e-20 + previousX.norm() * ef->lastX.norm());previousX = ef->lastX;if(std::isfinite(incDirChange) && (setting_solverMode & SOLVER_STEPMOMENTUM)){float newStepsize = exp(incDirChange * 1.4);if(incDirChange < 0 && stepsize>1) stepsize = 1;stepsize = sqrtf(sqrtf(newStepsize * stepsize * stepsize * stepsize));if(stepsize > 2) stepsize=2;if(stepsize <0.25) stepsize=0.25;} //優(yōu)化結果生效應該是修改各個待優(yōu)化參數(shù)值 //并通過評估本次增量的大小來判斷是否結束迭代 //待優(yōu)化參數(shù)包括M個點的逆深度 m * 8 + 4的相機位姿 仿射 相機參數(shù)bool canbreak = doStepFromBackup(stepsize, stepsize, stepsize, stepsize, stepsize);// eval new energy!評估新能量//用上面修改的新數(shù)據(jù)計算新的能量值newEnergy,并且重新計算一組//相關導數(shù)Vec3 newEnergy = linearizeAll(false);double newEnergyL = calcLEnergy();//返回0 不用去費腦子了double newEnergyM = calcMEnergy();//返回0不用去費腦子了if(!setting_debugout_runquiet){printf("%s %d (L %.2f, dir %.2f, ss %.1f): \t",(newEnergy[0] + newEnergy[1] + newEnergyL + newEnergyM <lastEnergy[0] + lastEnergy[1] + lastEnergyL + lastEnergyM) ? "ACCEPT" : "REJECT",iteration,log10(lambda),incDirChange,stepsize);printOptRes(newEnergy, newEnergyL, newEnergyM , 0, 0, frameHessians.back()->aff_g2l().a, frameHessians.back()->aff_g2l().b);}if(setting_forceAceptStep || (newEnergy[0] + newEnergy[1] + newEnergyL + newEnergyM <lastEnergy[0] + lastEnergy[1] + lastEnergyL + lastEnergyM)){if(multiThreading)treadReduce.reduce(boost::bind(&FullSystem::applyRes_Reductor, this, true, _1, _2, _3, _4), 0, activeResiduals.size(), 50);else{//中間變量計算applyRes_Reductor(true,0,activeResiduals.size(),0,0);}lastEnergy = newEnergy;lastEnergyL = newEnergyL;lastEnergyM = newEnergyM;lambda *= 0.25;}else{//能量升高了就使用 FullSystem::loadSateBackup() 將結果回滾。loadSateBackup();//重新算一次lastEnergy = linearizeAll(false);lastEnergyL = calcLEnergy();lastEnergyM = calcMEnergy();lambda *= 1e2;}if(canbreak && iteration >= setting_minOptIterations) break;}Vec10 newStateZero = Vec10::Zero();newStateZero.segment<2>(6) = frameHessians.back()->get_state().segment<2>(6);//setStateZero賦值的地方 用newStateZero賦值frameHessians.back()->setEvalPT(frameHessians.back()->PRE_worldToCam, newStateZero);EFDeltaValid = false;EFAdjointsValid = false;ef->setAdjointsF(&Hcalib);setPrecalcValues();//在跳出循環(huán)體之后調用一次 FullSystem::linearizeAll(true), //效果是將優(yōu)化之后成為 outlier 的 residual 剔除,剩下 //正常的 residual 調用一次 EFResidual::takeDataF() 計算新的 //EFResidual::JpJdF (這里涉及到 FEJ)。注意一下 lastEnergy = linearizeAll(true);if(!std::isfinite((double)lastEnergy[0]) || !std::isfinite((double)lastEnergy[1]) || !std::isfinite((double)lastEnergy[2])){printf("KF Tracking failed: LOST!\n");isLost=true;}statistics_lastFineTrackRMSE = sqrtf((float)(lastEnergy[0] / (patternNum*ef->resInA)));if(calibLog != 0){(*calibLog) << Hcalib.value_scaled.transpose() <<" " << frameHessians.back()->get_state_scaled().transpose() <<" " << sqrtf((float)(lastEnergy[0] / (patternNum*ef->resInA))) <<" " << ef->resInM << "\n";calibLog->flush();}//最終在這要更新關鍵幀的位姿和仿射參數(shù) 。用優(yōu)化后的值更新。{boost::unique_lock<boost::mutex> crlock(shellPoseMutex);//循環(huán)關鍵幀窗口for(FrameHessian* fh : frameHessians){fh->shell->camToWorld = fh->PRE_camToWorld;fh->shell->aff_g2l = fh->aff_g2l();}}debugPlotTracking();//返回的這個值是點的平均殘差值的開方return sqrtf((float)(lastEnergy[0] / (patternNum * ef->resInA)));}void FullSystem::solveSystem(int iteration, double lambda) { //零空間給lastNullspaces_pose他們幾個賦值呢,affA affB壓根沒用到 不用去理會ef->lastNullspaces_forLogging = getNullspaces(ef->lastNullspaces_pose,ef->lastNullspaces_scale,ef->lastNullspaces_affA,ef->lastNullspaces_affB); //解方程的主函數(shù)ef->solveSystemF(iteration, lambda,&Hcalib); }double FullSystem::calcLEnergy() {if(setting_forceAceptStep) return 0;double Ef = ef->calcLEnergyF_MT();return Ef;}void FullSystem::removeOutliers() {int numPointsDropped=0;for(FrameHessian* fh : frameHessians){for(unsigned int i=0;i<fh->pointHessians.size();i++){PointHessian* ph = fh->pointHessians[i];if(ph==0) continue;if(ph->residuals.size() == 0){fh->pointHessiansOut.push_back(ph);ph->efPoint->stateFlag = EFPointStatus::PS_DROP;fh->pointHessians[i] = fh->pointHessians.back();fh->pointHessians.pop_back();i--;numPointsDropped++;}}}ef->dropPointsF(); }std::vector<VecX> FullSystem::getNullspaces(std::vector<VecX> &nullspaces_pose1,std::vector<VecX> &nullspaces_scale1,std::vector<VecX> &nullspaces_affA,std::vector<VecX> &nullspaces_affB) { // 先做個清空nullspaces_pose1.clear();nullspaces_scale1.clear();nullspaces_affA.clear();nullspaces_affB.clear();int n = CPARS + frameHessians.size() * 8;std::vector<VecX> nullspaces_x0_pre;for(int i = 0; i < 6; i++){VecX nullspace_x0(n);nullspace_x0.setZero();for(FrameHessian* fh : frameHessians){nullspace_x0.segment<6>(CPARS+fh->idx * 8) = fh->nullspaces_pose.col(i);nullspace_x0.segment<3>(CPARS+fh->idx * 8) *= SCALE_XI_TRANS_INVERSE;nullspace_x0.segment<3>(CPARS+fh->idx * 8 + 3) *= SCALE_XI_ROT_INVERSE;}nullspaces_x0_pre.push_back(nullspace_x0);nullspaces_pose1.push_back(nullspace_x0);}for(int i=0;i<2;i++){VecX nullspace_x0(n);nullspace_x0.setZero();for(FrameHessian* fh : frameHessians){nullspace_x0.segment<2>(CPARS+fh->idx*8+6) = fh->nullspaces_affine.col(i).head<2>();nullspace_x0[CPARS+fh->idx*8+6] *= SCALE_A_INVERSE;nullspace_x0[CPARS+fh->idx*8+7] *= SCALE_B_INVERSE;}nullspaces_x0_pre.push_back(nullspace_x0);if(i==0) nullspaces_affA.push_back(nullspace_x0);if(i==1) nullspaces_affB.push_back(nullspace_x0);}VecX nullspace_x0(n);nullspace_x0.setZero();for(FrameHessian* fh : frameHessians){nullspace_x0.segment<6>(CPARS+fh->idx*8) = fh->nullspaces_scale;nullspace_x0.segment<3>(CPARS+fh->idx*8) *= SCALE_XI_TRANS_INVERSE;nullspace_x0.segment<3>(CPARS+fh->idx*8+3) *= SCALE_XI_ROT_INVERSE;}nullspaces_x0_pre.push_back(nullspace_x0);nullspaces_scale1.push_back(nullspace_x0);return nullspaces_x0_pre; }}

?

/** * This file is part of DSO. * * Copyright 2016 Technical University of Munich and Intel. * Developed by Jakob Engel <engelj at in dot tum dot de>, * for more information see <http://vision.in.tum.de/dso>. * If you use this code, please cite the respective publications as * listed on the above website. * * DSO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DSO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DSO. If not, see <http://www.gnu.org/licenses/>. */#include "OptimizationBackend/AccumulatedSCHessian.h" #include "OptimizationBackend/EnergyFunctional.h" #include "OptimizationBackend/EnergyFunctionalStructs.h"#include "FullSystem/HessianBlocks.h"namespace dso {void AccumulatedSCHessianSSE::addPoint(EFPoint* p, bool shiftPriorToZero, int tid) {int ngoodres = 0;for(EFResidual* r : p->residualsAll) if(r->isActive()) ngoodres++;if(ngoodres==0){p->HdiF=0;p->bdSumF=0;p->data->idepth_hessian=0;p->data->maxRelBaseline=0;return;} //float H = p->Hdd_accAF+p->Hdd_accLF+p->priorF;if(H < 1e-10) H = 1e-10;p->data->idepth_hessian=H;p->HdiF = 1.0 / H;//bdSumF是殘差*殘差對逆深度的偏導p->bdSumF = p->bd_accAF + p->bd_accLF;if(shiftPriorToZero) p->bdSumF += p->priorF*p->deltaF;VecCf Hcd = p->Hcd_accAF + p->Hcd_accLF;accHcc[tid].update(Hcd,Hcd,p->HdiF);//4*4對應相機參數(shù)accbc[tid].update(Hcd, p->bdSumF * p->HdiF);//4*1對應相機參數(shù)與殘差assert(std::isfinite((float)(p->HdiF)));int nFrames2 = nframes[tid]*nframes[tid];for(EFResidual* r1 : p->residualsAll){if(!r1->isActive()) continue;int r1ht = r1->hostIDX + r1->targetIDX*nframes[tid];for(EFResidual* r2 : p->residualsAll){if(!r2->isActive()) continue; //8*8矩陣對應位姿和光度accD[tid][r1ht+r2->targetIDX*nFrames2].update(r1->JpJdF, r2->JpJdF, p->HdiF);//}accE[tid][r1ht].update(r1->JpJdF, Hcd, p->HdiF);//位姿光度與相機參數(shù) 8*4accEB[tid][r1ht].update(r1->JpJdF,p->HdiF * p->bdSumF);//8*1 位姿光度與殘差} } void AccumulatedSCHessianSSE::stitchDoubleInternal(MatXX* H, VecX* b, EnergyFunctional const * const EF,int min, int max, Vec10* stats, int tid) {int toAggregate = NUM_THREADS;if(tid == -1) { toAggregate = 1; tid = 0; } // special case: if we dont do multithreading, dont aggregate.if(min==max) return;int nf = nframes[0];int nframes2 = nf*nf;for(int k=min;k<max;k++){int i = k%nf;int j = k/nf;int iIdx = CPARS+i*8;int jIdx = CPARS+j*8;int ijIdx = i+nf*j;Mat8C Hpc = Mat8C::Zero();Vec8 bp = Vec8::Zero();for(int tid2=0;tid2 < toAggregate;tid2++){accE[tid2][ijIdx].finish();accEB[tid2][ijIdx].finish();Hpc += accE[tid2][ijIdx].A1m.cast<double>();bp += accEB[tid2][ijIdx].A1m.cast<double>();}H[tid].block<8,CPARS>(iIdx,0) += EF->adHost[ijIdx] * Hpc;H[tid].block<8,CPARS>(jIdx,0) += EF->adTarget[ijIdx] * Hpc;b[tid].segment<8>(iIdx) += EF->adHost[ijIdx] * bp;b[tid].segment<8>(jIdx) += EF->adTarget[ijIdx] * bp;for(int k=0;k<nf;k++){int kIdx = CPARS+k*8;int ijkIdx = ijIdx + k*nframes2;int ikIdx = i+nf*k;Mat88 accDM = Mat88::Zero();for(int tid2=0;tid2 < toAggregate;tid2++){accD[tid2][ijkIdx].finish();if(accD[tid2][ijkIdx].num == 0) continue;accDM += accD[tid2][ijkIdx].A1m.cast<double>();}H[tid].block<8,8>(iIdx, iIdx) += EF->adHost[ijIdx] * accDM * EF->adHost[ikIdx].transpose();H[tid].block<8,8>(jIdx, kIdx) += EF->adTarget[ijIdx] * accDM * EF->adTarget[ikIdx].transpose();H[tid].block<8,8>(jIdx, iIdx) += EF->adTarget[ijIdx] * accDM * EF->adHost[ikIdx].transpose();H[tid].block<8,8>(iIdx, kIdx) += EF->adHost[ijIdx] * accDM * EF->adTarget[ikIdx].transpose();}}if(min==0){for(int tid2=0;tid2 < toAggregate;tid2++){accHcc[tid2].finish();accbc[tid2].finish();H[tid].topLeftCorner<CPARS,CPARS>() += accHcc[tid2].A1m.cast<double>();b[tid].head<CPARS>() += accbc[tid2].A1m.cast<double>();}}// // ----- new: copy transposed parts for calibration only. // for(int h=0;h<nf;h++) // { // int hIdx = 4+h*8; // H.block<4,8>(0,hIdx).noalias() = H.block<8,4>(hIdx,0).transpose(); // } }void AccumulatedSCHessianSSE::stitchDouble(MatXX &H, VecX &b, EnergyFunctional const * const EF, int tid) {int nf = nframes[0];int nframes2 = nf*nf;H = MatXX::Zero(nf*8+CPARS, nf*8+CPARS);b = VecX::Zero(nf*8+CPARS);for(int i=0;i<nf;i++)for(int j=0;j<nf;j++){int iIdx = CPARS+i*8;int jIdx = CPARS+j*8;int ijIdx = i+nf*j;accE[tid][ijIdx].finish();accEB[tid][ijIdx].finish();Mat8C accEM = accE[tid][ijIdx].A1m.cast<double>();Vec8 accEBV = accEB[tid][ijIdx].A1m.cast<double>();H.block<8,CPARS>(iIdx,0) += EF->adHost[ijIdx] * accEM;H.block<8,CPARS>(jIdx,0) += EF->adTarget[ijIdx] * accEM;b.segment<8>(iIdx) += EF->adHost[ijIdx] * accEBV;b.segment<8>(jIdx) += EF->adTarget[ijIdx] * accEBV;for(int k=0;k<nf;k++){int kIdx = CPARS+k*8;int ijkIdx = ijIdx + k*nframes2;int ikIdx = i+nf*k;accD[tid][ijkIdx].finish();if(accD[tid][ijkIdx].num == 0) continue;Mat88 accDM = accD[tid][ijkIdx].A1m.cast<double>();H.block<8,8>(iIdx, iIdx) += EF->adHost[ijIdx] * accDM * EF->adHost[ikIdx].transpose();H.block<8,8>(jIdx, kIdx) += EF->adTarget[ijIdx] * accDM * EF->adTarget[ikIdx].transpose();H.block<8,8>(jIdx, iIdx) += EF->adTarget[ijIdx] * accDM * EF->adHost[ikIdx].transpose();H.block<8,8>(iIdx, kIdx) += EF->adHost[ijIdx] * accDM * EF->adTarget[ikIdx].transpose();}}accHcc[tid].finish();accbc[tid].finish();H.topLeftCorner<CPARS,CPARS>() = accHcc[tid].A1m.cast<double>();b.head<CPARS>() = accbc[tid].A1m.cast<double>();// ----- new: copy transposed parts for calibration only.for(int h=0;h<nf;h++){int hIdx = CPARS+h*8;H.block<CPARS,8>(0,hIdx).noalias() = H.block<8,CPARS>(hIdx,0).transpose();} }}

?

/** * This file is part of DSO. * * Copyright 2016 Technical University of Munich and Intel. * Developed by Jakob Engel <engelj at in dot tum dot de>, * for more information see <http://vision.in.tum.de/dso>. * If you use this code, please cite the respective publications as * listed on the above website. * * DSO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DSO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DSO. If not, see <http://www.gnu.org/licenses/>. */#include "OptimizationBackend/AccumulatedTopHessian.h" #include "OptimizationBackend/EnergyFunctional.h" #include "OptimizationBackend/EnergyFunctionalStructs.h" #include <iostream>#if !defined(__SSE3__) && !defined(__SSE2__) && !defined(__SSE1__) #include "SSE2NEON.h" #endifnamespace dso {//函數(shù)計算了 Hessian 矩陣。而這里的 Hessian 矩陣是存儲了兩個幀之間的相互信息, //此函數(shù)在mode為1的時候一直continue 不執(zhí)行循環(huán)體里面的內(nèi)容template<int mode> void AccumulatedTopHessianSSE::addPoint(EFPoint* p, EnergyFunctional const * const ef1, int tid) // 0 = active, 1 = linearized, 2=marginalize {assert(mode==0 || mode==1 || mode==2);VecCf dc = ef1->cDeltaF;float dd = p->deltaF;float bd_acc=0;float Hdd_acc=0;VecCf Hcd_acc = VecCf::Zero();//printf("====nframes[tid]====%d\n", nframes[tid]);//遍歷p點對應的殘差for(EFResidual* r : p->residualsAll){if(mode==0){if(r->isLinearized || !r->isActive()) continue;}if(mode==1){if(!r->isLinearized || !r->isActive()) continue;}if(mode==2){if(!r->isActive()) continue;assert(r->isLinearized);}RawResidualJacobian* rJ = r->J;//host與target 兩幀對應關系唯一編號int htIDX = r->hostIDX + r->targetIDX*nframes[tid];Mat18f dp = ef1->adHTdeltaF[htIDX];//殘差值VecNRf resApprox; if(mode==0)resApprox = rJ->resF;//殘差值 在前面函數(shù)預預算出來的if(mode==2)resApprox = r->res_toZeroF;if(mode==1)//linearized residual 是不存在的。{// compute Jp*delta__m128 Jp_delta_x = _mm_set1_ps(rJ->Jpdxi[0].dot(dp.head<6>())+rJ->Jpdc[0].dot(dc)+rJ->Jpdd[0]*dd);__m128 Jp_delta_y = _mm_set1_ps(rJ->Jpdxi[1].dot(dp.head<6>())+rJ->Jpdc[1].dot(dc)+rJ->Jpdd[1]*dd);__m128 delta_a = _mm_set1_ps((float)(dp[6]));__m128 delta_b = _mm_set1_ps((float)(dp[7]));for(int i=0;i<patternNum;i+=4){// PATTERN: rtz = resF - [JI*Jp Ja]*delta.__m128 rtz = _mm_load_ps(((float*)&r->res_toZeroF)+i);rtz = _mm_add_ps(rtz,_mm_mul_ps(_mm_load_ps(((float*)(rJ->JIdx))+i),Jp_delta_x));rtz = _mm_add_ps(rtz,_mm_mul_ps(_mm_load_ps(((float*)(rJ->JIdx+1))+i),Jp_delta_y));rtz = _mm_add_ps(rtz,_mm_mul_ps(_mm_load_ps(((float*)(rJ->JabF))+i),delta_a));rtz = _mm_add_ps(rtz,_mm_mul_ps(_mm_load_ps(((float*)(rJ->JabF+1))+i),delta_b));_mm_store_ps(((float*)&resApprox)+i, rtz);}}// need to compute JI^T * r, and Jab^T * r. (both are 2-vectors).Vec2f JI_r(0,0);//Vec2f Jab_r(0,0);//誤差平方和float rr = 0;for(int i = 0; i < patternNum; i++){//resApprox是誤差向量1*8對應8個點相當于fx*//殘差值* 殘差對坐標求偏導JI_r[0] += resApprox[i] * rJ->JIdx[0][i];JI_r[1] += resApprox[i] * rJ->JIdx[1][i];//殘差值* 殘差對光度系數(shù)求偏導Jab_r[0] += resApprox[i] * rJ->JabF[0][i];Jab_r[1] += resApprox[i] * rJ->JabF[1][i];//殘差值* 殘差值rr += resApprox[i] * resApprox[i];}//這段是更新H (13*13)這個矩陣 ,其中存儲的是兩幀之間的互信息 //htIDX就相當于信息編號 累加所有host_frame 與target_frame之間的所有 //殘差項的互信息 有幾個對應關系就填充幾個H13*13的矩陣。 //例如窗口內(nèi)有8幀那么對應關系就有64個。 //其中有個位置需要注意當host與target是同一幀的時候。這個13*13的 //矩陣為0矩陣 因為自己對自己求殘差 殘差為0所有的偏導都為0 //這個就是acc[tid][htIDX].update(rJ->Jpdc[0].data(), rJ->Jpdxi[0].data(),rJ->Jpdc[1].data(), rJ->Jpdxi[1].data(),rJ->JIdx2(0,0),rJ->JIdx2(0,1),rJ->JIdx2(1,1));acc[tid][htIDX].updateBotRight(rJ->Jab2(0,0), rJ->Jab2(0,1), Jab_r[0],rJ->Jab2(1,1), Jab_r[1],rr);acc[tid][htIDX].updateTopRight(rJ->Jpdc[0].data(), rJ->Jpdxi[0].data(),rJ->Jpdc[1].data(), rJ->Jpdxi[1].data(),rJ->JabJIdx(0,0), rJ->JabJIdx(0,1),rJ->JabJIdx(1,0), rJ->JabJIdx(1,1),JI_r[0], JI_r[1]);//下面這三個求和是優(yōu)化點逆深度用的 //計算每一個點對于所有 residual 的信息和 //是殘差對坐標偏導的轉置*殘差對坐標偏導*坐標對逆深度偏導 // 最終結果就是:殘差對坐標的偏導的轉置* 殘差對逆深度的偏導Vec2f Ji2_Jpdd = rJ->JIdx2 * rJ->Jpdd; //殘差* 殘差對逆深度的偏導bd_acc += JI_r[0] * rJ->Jpdd[0] + JI_r[1] * rJ->Jpdd[1]; //是 殘差對逆深度的偏導的轉置*殘差對逆深度的偏導Hdd_acc += Ji2_Jpdd.dot(rJ->Jpdd);//殘差對相機參數(shù)的 偏導的轉置*殘差點對逆深度的偏導Hcd_acc += rJ->Jpdc[0] * Ji2_Jpdd[0] + rJ->Jpdc[1] * Ji2_Jpdd[1];nres[tid]++;}//如果這個點是 active 點,那么設置AF相關的變量,否則設置LF相關變量,//如果是 marginalize 點,清除AF相關變量的信息。這三個成員變量將用于計//算逆深度的優(yōu)化量。if(mode==0){p->Hdd_accAF = Hdd_acc;p->bd_accAF = bd_acc;p->Hcd_accAF = Hcd_acc;}if(mode==1 || mode==2){p->Hdd_accLF = Hdd_acc;p->bd_accLF = bd_acc;p->Hcd_accLF = Hcd_acc;}if(mode==2){p->Hcd_accAF.setZero();p->Hdd_accAF = 0;p->bd_accAF = 0;} } template void AccumulatedTopHessianSSE::addPoint<0>(EFPoint* p, EnergyFunctional const * const ef1, int tid); template void AccumulatedTopHessianSSE::addPoint<1>(EFPoint* p, EnergyFunctional const * const ef1, int tid); template void AccumulatedTopHessianSSE::addPoint<2>(EFPoint* p, EnergyFunctional const * const ef1, int tid);void AccumulatedTopHessianSSE::stitchDouble(MatXX &H, VecX &b, EnergyFunctional const * const EF, bool usePrior, bool useDelta, int tid) {H = MatXX::Zero(nframes[tid]*8+CPARS, nframes[tid]*8+CPARS);b = VecX::Zero(nframes[tid]*8+CPARS);for(int h=0;h<nframes[tid];h++)for(int t=0;t<nframes[tid];t++){int hIdx = CPARS+h*8;int tIdx = CPARS+t*8;int aidx = h+nframes[tid]*t;acc[tid][aidx].finish();if(acc[tid][aidx].num==0) continue;MatPCPC accH = acc[tid][aidx].H.cast<double>();H.block<8,8>(hIdx, hIdx).noalias() += EF->adHost[aidx] * accH.block<8,8>(CPARS,CPARS) * EF->adHost[aidx].transpose();H.block<8,8>(tIdx, tIdx).noalias() += EF->adTarget[aidx] * accH.block<8,8>(CPARS,CPARS) * EF->adTarget[aidx].transpose();H.block<8,8>(hIdx, tIdx).noalias() += EF->adHost[aidx] * accH.block<8,8>(CPARS,CPARS) * EF->adTarget[aidx].transpose();H.block<8,CPARS>(hIdx,0).noalias() += EF->adHost[aidx] * accH.block<8,CPARS>(CPARS,0);H.block<8,CPARS>(tIdx,0).noalias() += EF->adTarget[aidx] * accH.block<8,CPARS>(CPARS,0);H.topLeftCorner<CPARS,CPARS>().noalias() += accH.block<CPARS,CPARS>(0,0);b.segment<8>(hIdx).noalias() += EF->adHost[aidx] * accH.block<8,1>(CPARS,8+CPARS);b.segment<8>(tIdx).noalias() += EF->adTarget[aidx] * accH.block<8,1>(CPARS,8+CPARS);b.head<CPARS>().noalias() += accH.block<CPARS,1>(0,8+CPARS);}// ----- new: copy transposed parts.for(int h=0;h<nframes[tid];h++){int hIdx = CPARS+h*8;H.block<CPARS,8>(0,hIdx).noalias() = H.block<8,CPARS>(hIdx,0).transpose();for(int t=h+1;t<nframes[tid];t++){int tIdx = CPARS+t*8;H.block<8,8>(hIdx, tIdx).noalias() += H.block<8,8>(tIdx, hIdx).transpose();H.block<8,8>(tIdx, hIdx).noalias() = H.block<8,8>(hIdx, tIdx).transpose();}}if(usePrior){assert(useDelta);H.diagonal().head<CPARS>() += EF->cPrior;b.head<CPARS>() += EF->cPrior.cwiseProduct(EF->cDeltaF.cast<double>());for(int h=0;h<nframes[tid];h++){H.diagonal().segment<8>(CPARS+h*8) += EF->frames[h]->prior;b.segment<8>(CPARS+h*8) += EF->frames[h]->prior.cwiseProduct(EF->frames[h]->delta_prior);}} }void AccumulatedTopHessianSSE::stitchDoubleInternal(MatXX* H, VecX* b, EnergyFunctional const * const EF, bool usePrior,int min, int max, Vec10* stats, int tid) {int toAggregate = NUM_THREADS;if(tid == -1) { toAggregate = 1; tid = 0; } // special case: if we dont do multithreading, dont aggregate.if(min==max) return;//遍歷 所有(host_frame, target_frame)組合for(int k=min;k<max;k++){int h = k%nframes[0];int t = k/nframes[0];int hIdx = CPARS + h * 8;//int tIdx = CPARS + t * 8;////表示的是第幾個組合==>編號,組合數(shù)一共64個int aidx = h + nframes[0] * t;assert(aidx == k);//13*13大小MatPCPC accH = MatPCPC::Zero();//內(nèi)層循環(huán)累積計算accH,這個循環(huán)是用于累加多個線程的結果for(int tid2 = 0; tid2 < toAggregate; tid2++){acc[tid2][aidx].finish();if(acc[tid2][aidx].num==0) continue;accH += acc[tid2][aidx].H.cast<double>();//accH就是acc[h + nframes[0] * t]}//下面的H對應 Hxx JTXr 對應b 使用了 EnergyFunctional::adHost 和 //EnergyFunctional::adTarget。這是因為前面計算的 Jacobian 都是對//相對狀態(tài)的偏導,這兩個變量存儲的是相對狀態(tài)對絕//對狀態(tài)的偏導//H.block<8,8>(hIdx, hIdx) 是提取H矩陣(hIdx,hIdx)為起始位大小為8行*8 列 的塊//這個H存儲的是殘差對host幀絕對位姿(w - h)和光度的增量的偏導//對照公式推一下才明白//host幀相對自己的 位姿轉換為絕對位姿的代碼H[tid].block<8,8>(hIdx, hIdx).noalias() += EF->adHost[aidx] * accH.block<8,8>(CPARS,CPARS) * EF->adHost[aidx].transpose();//target幀相對自己的 位姿轉換為絕對位姿的代碼H[tid].block<8,8>(tIdx, tIdx).noalias() += EF->adTarget[aidx] * accH.block<8,8>(CPARS,CPARS) * EF->adTarget[aidx].transpose();// host幀相對target值 的 位姿轉換為絕對位姿的代碼H[tid].block<8,8>(hIdx, tIdx).noalias() += EF->adHost[aidx] * accH.block<8,8>(CPARS,CPARS) * EF->adTarget[aidx].transpose();//H[tid].block<8,CPARS>(hIdx,0).noalias() += EF->adHost[aidx] * accH.block<8,CPARS>(CPARS,0);H[tid].block<8,CPARS>(tIdx,0).noalias() += EF->adTarget[aidx] * accH.block<8,CPARS>(CPARS,0); //每次都把相機參數(shù)的放在左上角累加H[tid].topLeftCorner<CPARS,CPARS>().noalias() += accH.block<CPARS,CPARS>(0,0);b[tid].segment<8>(hIdx).noalias() += EF->adHost[aidx] * accH.block<8,1>(CPARS,CPARS+8);b[tid].segment<8>(tIdx).noalias() += EF->adTarget[aidx] * accH.block<8,1>(CPARS,CPARS+8);b[tid].head<CPARS>().noalias() += accH.block<CPARS,1>(0,CPARS+8);}// only do this on one thread.if(min==0 && usePrior){//H對角矩陣H[tid].diagonal().head<CPARS>() += EF->cPrior;b[tid].head<CPARS>() += EF->cPrior.cwiseProduct(EF->cDeltaF.cast<double>());for(int h=0;h<nframes[tid];h++){//segment獲取CPARS+h*8為起始點的 8個元素H[tid].diagonal().segment<8>(CPARS+h*8) += EF->frames[h]->prior;b[tid].segment<8>(CPARS+h*8) += EF->frames[h]->prior.cwiseProduct(EF->frames[h]->delta_prior);}} }}

?

/** * This file is part of DSO. * * Copyright 2016 Technical University of Munich and Intel. * Developed by Jakob Engel <engelj at in dot tum dot de>, * for more information see <http://vision.in.tum.de/dso>. * If you use this code, please cite the respective publications as * listed on the above website. * * DSO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DSO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DSO. If not, see <http://www.gnu.org/licenses/>. */#pragma once#include "util/NumType.h" #include "OptimizationBackend/MatrixAccumulators.h" #include "vector" #include <math.h> #include "util/IndexThreadReduce.h"namespace dso {class EFPoint; class EnergyFunctional;class AccumulatedTopHessianSSE { public:EIGEN_MAKE_ALIGNED_OPERATOR_NEW;inline AccumulatedTopHessianSSE(){for(int tid=0;tid < NUM_THREADS; tid++){nres[tid]=0;acc[tid]=0;nframes[tid]=0;}};inline ~AccumulatedTopHessianSSE(){for(int tid=0;tid < NUM_THREADS; tid++){if(acc[tid] != 0) delete[] acc[tid];}};inline void setZero(int nFrames, int min=0, int max=1, Vec10* stats=0, int tid=0){if(nFrames != nframes[tid]){if(acc[tid] != 0) delete[] acc[tid]; #if USE_XI_MODELacc[tid] = new Accumulator14[nFrames*nFrames]; #elseacc[tid] = new AccumulatorApprox[nFrames*nFrames]; #endif}for(int i=0;i<nFrames*nFrames;i++){ acc[tid][i].initialize(); }nframes[tid]=nFrames;nres[tid]=0;}void stitchDouble(MatXX &H, VecX &b, EnergyFunctional const * const EF, bool usePrior, bool useDelta, int tid=0);template<int mode> void addPoint(EFPoint* p, EnergyFunctional const * const ef1, int tid=0);void stitchDoubleMT(IndexThreadReduce<Vec10>* red, MatXX &H, VecX &b, EnergyFunctional const * const EF, bool usePrior, bool MT){// sum up, splitting by bock in square.if(MT){MatXX Hs[NUM_THREADS];VecX bs[NUM_THREADS];for(int i=0;i<NUM_THREADS;i++){assert(nframes[0] == nframes[i]);Hs[i] = MatXX::Zero(nframes[0]*8+CPARS, nframes[0]*8+CPARS);bs[i] = VecX::Zero(nframes[0]*8+CPARS);}red->reduce(boost::bind(&AccumulatedTopHessianSSE::stitchDoubleInternal,this,Hs, bs, EF, usePrior, _1, _2, _3, _4), 0, nframes[0]*nframes[0], 0);// sum up resultsH = Hs[0];b = bs[0];for(int i=1;i<NUM_THREADS;i++){H.noalias() += Hs[i];b.noalias() += bs[i];nres[0] += nres[i];}}else{//nframes[0] = 8//這里的H是一個68x68的矩陣(//假設系統(tǒng)已穩(wěn)定,當前滑動窗口中有8個關鍵幀//),其中左上角4x4 小塊是關于相//機內(nèi)參的。這里通過遍歷將每條邊所屬的Hessian//信息加入到總的Hessian矩陣中,這里的EF->adHost和//EF->adTarget分別表示第4.5節(jié)所計算得到的相對位姿增量對//host幀和target幀的絕對位姿增量的偏導數(shù)//這樣就把前面acc里得到的相對位姿的信息轉變//為絕對位姿的信息。H = MatXX::Zero(nframes[0] * 8 + CPARS, nframes[0] * 8 + CPARS);//68 * 68b = VecX::Zero(nframes[0] * 8 + CPARS);stitchDoubleInternal(&H, &b, EF, usePrior, 0, nframes[0] * nframes[0], 0, -1);}// make diagonal by copying over parts.//通過復制填充H矩陣for(int h = 0; h < nframes[0]; h++){int hIdx = CPARS + h * 8;H.block<CPARS,8>(0, hIdx).noalias() = H.block<8,CPARS>(hIdx, 0).transpose();for(int t = h + 1; t < nframes[0]; t++){int tIdx = CPARS + t * 8;H.block<8, 8>(hIdx, tIdx).noalias() += H.block<8, 8>(tIdx, hIdx).transpose();H.block<8, 8>(tIdx, hIdx).noalias() = H.block<8, 8>(hIdx, tIdx).transpose();}}}int nframes[NUM_THREADS];EIGEN_ALIGN16 AccumulatorApprox* acc[NUM_THREADS];int nres[NUM_THREADS];template<int mode> void addPointsInternal(std::vector<EFPoint*>* points, EnergyFunctional const * const ef1,int min=0, int max=1, Vec10* stats=0, int tid=0){for(int i=min;i<max;i++) addPoint<mode>((*points)[i],ef1,tid);}private:void stitchDoubleInternal(MatXX* H, VecX* b, EnergyFunctional const * const EF, bool usePrior,int min, int max, Vec10* stats, int tid); }; }

?

/** * This file is part of DSO. * * Copyright 2016 Technical University of Munich and Intel. * Developed by Jakob Engel <engelj at in dot tum dot de>, * for more information see <http://vision.in.tum.de/dso>. * If you use this code, please cite the respective publications as * listed on the above website. * * DSO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DSO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DSO. If not, see <http://www.gnu.org/licenses/>. */#include "OptimizationBackend/EnergyFunctional.h" #include "OptimizationBackend/EnergyFunctionalStructs.h" #include "FullSystem/FullSystem.h" #include "FullSystem/HessianBlocks.h" #include "FullSystem/Residuals.h" #include "OptimizationBackend/AccumulatedSCHessian.h" #include "OptimizationBackend/AccumulatedTopHessian.h"#if !defined(__SSE3__) && !defined(__SSE2__) && !defined(__SSE1__) #include "SSE2NEON.h" #endifnamespace dso {bool EFAdjointsValid = false; bool EFIndicesValid = false; bool EFDeltaValid = false;// 這個函數(shù)得到博客<<跟蹤與優(yōu)化>>4.5節(jié)所述。優(yōu)化窗口中兩幀 //之間都會計算一個這個矩陣 void EnergyFunctional::setAdjointsF(CalibHessian* Hcalib) {if(adHost != 0) delete[] adHost;if(adTarget != 0) delete[] adTarget;adHost = new Mat88[nFrames*nFrames];adTarget = new Mat88[nFrames*nFrames];//遍歷隊列中的幀。for(int h=0;h<nFrames;h++)//nFrames幀數(shù)for(int t=0;t<nFrames;t++){FrameHessian* host = frames[h]->data;FrameHessian* target = frames[t]->data; //博客<<跟蹤與優(yōu)化>>H幀到T幀的相對位姿變換矩陣 4.5公式SE3 hostToTarget = target->get_worldToCam_evalPT() * host->get_worldToCam_evalPT().inverse();//初始化一個單位矩陣Mat88 AH = Mat88::Identity();Mat88 AT = Mat88::Identity();//求hostToTarget的伴隨矩陣的轉置//4.5.3AH.topLeftCorner<6,6>() = -hostToTarget.Adj().transpose();//4.5.2AT.topLeftCorner<6,6>() = Mat66::Identity();Vec2f affLL = AffLight::fromToVecExposure(host->ab_exposure, target->ab_exposure, host->aff_g2l_0(), target->aff_g2l_0()).cast<float>();AT(6,6) = -affLL[0];AH(6,6) = affLL[0];AT(7,7) = -1;AH(7,7) = affLL[0]; //block提取AH矩陣(0,0)為起始位大小為3行*8 列 的塊AH.block<3,8>(0,0) *= SCALE_XI_TRANS;AH.block<3,8>(3,0) *= SCALE_XI_ROT;AH.block<1,8>(6,0) *= SCALE_A;AH.block<1,8>(7,0) *= SCALE_B;AT.block<3,8>(0,0) *= SCALE_XI_TRANS;AT.block<3,8>(3,0) *= SCALE_XI_ROT;AT.block<1,8>(6,0) *= SCALE_A;AT.block<1,8>(7,0) *= SCALE_B;//th增量對hw增量的偏導 th屬于相對位姿增量hw為絕對位姿增量 下同adHost[h + t * nFrames] = AH;//th增量對tw增量的偏導adTarget[h + t * nFrames] = AT;}cPrior = VecC::Constant(setting_initialCalibHessian);if(adHostF != 0) delete[] adHostF;if(adTargetF != 0) delete[] adTargetF;adHostF = new Mat88f[nFrames*nFrames];adTargetF = new Mat88f[nFrames*nFrames]; //下面是將結果傳出去。 //結果內(nèi)容為相對位姿增量對絕對位姿增量的求導 . 還有仿射系數(shù) 矩陣 //維數(shù)是 8*8 //絕對位姿分別是host幀和target幀for(int h = 0; h < nFrames; h++)for(int t = 0; t < nFrames; t++){adHostF[h + t * nFrames] = adHost[h + t * nFrames].cast<float>();adTargetF[h + t * nFrames] = adTarget[h + t * nFrames].cast<float>();}cPriorF = cPrior.cast<float>();EFAdjointsValid = true; }EnergyFunctional::EnergyFunctional() {adHost=0;adTarget=0;red=0;adHostF=0;adTargetF=0;adHTdeltaF=0;nFrames = nResiduals = nPoints = 0;HM = MatXX::Zero(CPARS,CPARS);bM = VecX::Zero(CPARS);accSSE_top_L = new AccumulatedTopHessianSSE();accSSE_top_A = new AccumulatedTopHessianSSE();accSSE_bot = new AccumulatedSCHessianSSE();resInA = resInL = resInM = 0;currentLambda=0; } EnergyFunctional::~EnergyFunctional() {for(EFFrame* f : frames){for(EFPoint* p : f->points){for(EFResidual* r : p->residualsAll){r->data->efResidual=0;delete r;}p->data->efPoint=0;delete p;}f->data->efFrame=0;delete f;}if(adHost != 0) delete[] adHost;if(adTarget != 0) delete[] adTarget;if(adHostF != 0) delete[] adHostF;if(adTargetF != 0) delete[] adTargetF;if(adHTdeltaF != 0) delete[] adHTdeltaF;delete accSSE_top_L;delete accSSE_top_A;delete accSSE_bot; }void EnergyFunctional::setDeltaF(CalibHessian* HCalib) { //重新創(chuàng)建adHTdeltaFif(adHTdeltaF != 0) delete[] adHTdeltaF;//位姿與光度仿射系數(shù) 維度為1 *8 * 64(關鍵幀窗口內(nèi)有8幀的話)adHTdeltaF = new Mat18f[nFrames * nFrames];//遍歷關鍵幀for(int h = 0; h < nFrames; h++)for(int t = 0; t <nFrames; t++){//關鍵幀窗口配對的標簽 例如 窗口共有6幀 那么idx從0~35int idx = h + t * nFrames;//位姿與光度仿射變換的delta值 //-----------------------計算的是f(x) 對hw的偏導 + f(x)對tw的偏導 不太理解這塊//get_state_minus_stateZero().head<8>() 取的就是位姿和仿射變換的差值adHTdeltaF[idx] = frames[h]->data->get_state_minus_stateZero().head<8>().cast<float>().transpose() * adHostF[idx]+frames[t]->data->get_state_minus_stateZero().head<8>().cast<float>().transpose() * adTargetF[idx];}//相機的delta值cDeltaF = HCalib->value_minus_value_zero.cast<float>();//點逆深度的delta值for(EFFrame* f : frames){f->delta = f->data->get_state_minus_stateZero().head<8>();f->delta_prior = (f->data->get_state() - f->data->getPriorZero()).head<8>();for(EFPoint* p : f->points)p->deltaF = p->data->idepth - p->data->idepth_zero;}EFDeltaValid = true; }// accumulates & shifts L. void EnergyFunctional::accumulateAF_MT(MatXX &H, VecX &b, bool MT) {if(MT){red->reduce(boost::bind(&AccumulatedTopHessianSSE::setZero, accSSE_top_A, nFrames, _1, _2, _3, _4), 0, 0, 0);red->reduce(boost::bind(&AccumulatedTopHessianSSE::addPointsInternal<0>,accSSE_top_A, &allPoints, this, _1, _2, _3, _4), 0, allPoints.size(), 50);accSSE_top_A->stitchDoubleMT(red,H,b,this,false,true);resInA = accSSE_top_A->nres[0];//點總數(shù)應該是// printf("====resInA====%d\n", resInA);}else{accSSE_top_A->setZero(nFrames);//遍歷幀參與優(yōu)化的幀 其就是關鍵幀窗口內(nèi)的幀for(EFFrame* f : frames)for(EFPoint* p : f->points)//遍歷點accSSE_top_A->addPoint<0>(p,this);//具體計算H b的部分accSSE_top_A->stitchDoubleMT(red,H,b,this,false,false);resInA = accSSE_top_A->nres[0];} }// accumulates & shifts L. void EnergyFunctional::accumulateLF_MT(MatXX &H, VecX &b, bool MT) {if(MT){red->reduce(boost::bind(&AccumulatedTopHessianSSE::setZero, accSSE_top_L, nFrames, _1, _2, _3, _4), 0, 0, 0);red->reduce(boost::bind(&AccumulatedTopHessianSSE::addPointsInternal<1>,accSSE_top_L, &allPoints, this, _1, _2, _3, _4), 0, allPoints.size(), 50);accSSE_top_L->stitchDoubleMT(red,H,b,this,true,true);resInL = accSSE_top_L->nres[0];}else{accSSE_top_L->setZero(nFrames);for(EFFrame* f : frames)for(EFPoint* p : f->points)accSSE_top_L->addPoint<1>(p,this);accSSE_top_L->stitchDoubleMT(red,H,b,this,true,false);resInL = accSSE_top_L->nres[0];} }void EnergyFunctional::accumulateSCF_MT(MatXX &H, VecX &b, bool MT) {if(MT){red->reduce(boost::bind(&AccumulatedSCHessianSSE::setZero, accSSE_bot, nFrames, _1, _2, _3, _4), 0, 0, 0);red->reduce(boost::bind(&AccumulatedSCHessianSSE::addPointsInternal,accSSE_bot, &allPoints, true, _1, _2, _3, _4), 0, allPoints.size(), 50);accSSE_bot->stitchDoubleMT(red,H,b,this,true);}else{accSSE_bot->setZero(nFrames);for(EFFrame* f : frames)for(EFPoint* p : f->points)accSSE_bot->addPoint(p, true);accSSE_bot->stitchDoubleMT(red, H, b,this,false);} }void EnergyFunctional::resubstituteF_MT(VecX x, CalibHessian* HCalib, bool MT) {assert(x.size() == CPARS+nFrames*8);//計算 相機參數(shù) 位姿 仿射變換參數(shù)增量部分 schur消元后的gαVecXf xF = x.cast<float>();//gβ//相機參數(shù)的增量值HCalib->step = - x.head<CPARS>();Mat18f* xAd = new Mat18f[nFrames * nFrames];//相機參數(shù)增量VecCf cstep = xF.head<CPARS>();//遍歷窗口內(nèi)的幀for(EFFrame* h : frames){//相機位姿以及仿射增量h->data->step.head<8>() = - x.segment<8>(CPARS + 8 * h->idx);h->data->step.tail<2>().setZero();//遍歷窗口內(nèi)的幀for(EFFrame* t : frames){//絕對位姿增量* 相對位姿轉置對絕對位姿求偏導xAd[nFrames * h->idx + t->idx] = xF.segment<8>(CPARS + 8 * h->idx).transpose() * adHostF[h->idx+nFrames * t->idx]+ xF.segment<8>(CPARS + 8 * t->idx).transpose() * adTargetF[h->idx+nFrames * t->idx];}} //schur消元的另外一個增量求解 schur消元后的gβif(MT){red->reduce(boost::bind(&EnergyFunctional::resubstituteFPt,this, cstep, xAd, _1, _2, _3, _4), 0, allPoints.size(), 50);}else{//計算逆深度的增量部分的代碼resubstituteFPt(cstep, xAd, 0, allPoints.size(), 0, 0);}delete[] xAd; } //這個函數(shù)里計算的是逆深度的增量值 gα void EnergyFunctional::resubstituteFPt(const VecCf &xc, Mat18f* xAd, int min, int max, Vec10* stats, int tid) { //遍歷點for(int k = min; k < max; k++){EFPoint *p = allPoints[k];int ngoodres = 0;for(EFResidual *r : p->residualsAll) if(r->isActive()) ngoodres++;if(ngoodres==0){p->data->step = 0;continue;}//接著在這里幾行計算逆深度值的增量//b是殘差*殘差對逆深度的偏導 ---->之和float b = p->bdSumF;//xc是相機參數(shù)增量b -= xc.dot(p->Hcd_accAF + p->Hcd_accLF);//循環(huán)殘差項一個點對應多個殘差for(EFResidual* r : p->residualsAll){if(!r->isActive()) continue;//JpJdF 殘差對位姿的偏導的轉置* 殘差對逆深度的偏導b -= xAd[r->hostIDX * nFrames + r->targetIDX] * r->JpJdF;}// 逆深度的增量 存儲于p->data->step中p->data->step = -b * p->HdiF; assert(std::isfinite(p->data->step));} }double EnergyFunctional::calcMEnergyF() {assert(EFDeltaValid);assert(EFAdjointsValid);assert(EFIndicesValid);VecX delta = getStitchedDeltaF();return delta.dot(2*bM + HM*delta); }void EnergyFunctional::calcLEnergyPt(int min, int max, Vec10* stats, int tid) {Accumulator11 E;E.initialize();VecCf dc = cDeltaF;for(int i=min;i<max;i++){EFPoint* p = allPoints[i];float dd = p->deltaF;for(EFResidual* r : p->residualsAll){if(!r->isLinearized || !r->isActive()) continue;Mat18f dp = adHTdeltaF[r->hostIDX+nFrames*r->targetIDX];RawResidualJacobian* rJ = r->J;// compute Jp*deltafloat Jp_delta_x_1 = rJ->Jpdxi[0].dot(dp.head<6>())+rJ->Jpdc[0].dot(dc)+rJ->Jpdd[0]*dd;float Jp_delta_y_1 = rJ->Jpdxi[1].dot(dp.head<6>())+rJ->Jpdc[1].dot(dc)+rJ->Jpdd[1]*dd;__m128 Jp_delta_x = _mm_set1_ps(Jp_delta_x_1);__m128 Jp_delta_y = _mm_set1_ps(Jp_delta_y_1);__m128 delta_a = _mm_set1_ps((float)(dp[6]));__m128 delta_b = _mm_set1_ps((float)(dp[7]));for(int i=0;i+3<patternNum;i+=4){// PATTERN: E = (2*res_toZeroF + J*delta) * J*delta.__m128 Jdelta = _mm_mul_ps(_mm_load_ps(((float*)(rJ->JIdx))+i),Jp_delta_x);Jdelta = _mm_add_ps(Jdelta,_mm_mul_ps(_mm_load_ps(((float*)(rJ->JIdx+1))+i),Jp_delta_y));Jdelta = _mm_add_ps(Jdelta,_mm_mul_ps(_mm_load_ps(((float*)(rJ->JabF))+i),delta_a));Jdelta = _mm_add_ps(Jdelta,_mm_mul_ps(_mm_load_ps(((float*)(rJ->JabF+1))+i),delta_b));__m128 r0 = _mm_load_ps(((float*)&r->res_toZeroF)+i);r0 = _mm_add_ps(r0,r0);r0 = _mm_add_ps(r0,Jdelta);Jdelta = _mm_mul_ps(Jdelta,r0);E.updateSSENoShift(Jdelta);}for(int i=((patternNum>>2)<<2); i < patternNum; i++){float Jdelta = rJ->JIdx[0][i]*Jp_delta_x_1 + rJ->JIdx[1][i]*Jp_delta_y_1 +rJ->JabF[0][i]*dp[6] + rJ->JabF[1][i]*dp[7];E.updateSingleNoShift((float)(Jdelta * (Jdelta + 2*r->res_toZeroF[i])));}}E.updateSingle(p->deltaF*p->deltaF*p->priorF);}E.finish();(*stats)[0] += E.A; }double EnergyFunctional::calcLEnergyF_MT() {assert(EFDeltaValid);assert(EFAdjointsValid);assert(EFIndicesValid);double E = 0;//printf("=====EFFrame.size====%d\n", frames.size());for(EFFrame* f : frames)E += f->delta_prior.cwiseProduct(f->prior).dot(f->delta_prior);E += cDeltaF.cwiseProduct(cPriorF).dot(cDeltaF);red->reduce(boost::bind(&EnergyFunctional::calcLEnergyPt,this, _1, _2, _3, _4), 0, allPoints.size(), 50);return E+red->stats[0]; }EFResidual* EnergyFunctional::insertResidual(PointFrameResidual* r) {EFResidual* efr = new EFResidual(r, r->point->efPoint, r->host->efFrame, r->target->efFrame);efr->idxInAll = r->point->efPoint->residualsAll.size();r->point->efPoint->residualsAll.push_back(efr);connectivityMap[(((uint64_t)efr->host->frameID) << 32) + ((uint64_t)efr->target->frameID)][0]++;nResiduals++;r->efResidual = efr;return efr; } //只有關鍵幀才會nFrames自加 frames隊列中會增加成員 //此函數(shù)實現(xiàn)功能: 創(chuàng)建新幀的能量窗口目標,將其加入窗口隊列,改變BM HMD等尺寸 //重新計算窗口內(nèi)兩幀之間的相對增量對絕對增量的偏導,將新幀的點納入窗口總 //點隊列中。 EFFrame* EnergyFunctional::insertFrame(FrameHessian* fh, CalibHessian* Hcalib) {//創(chuàng)建EFFrame對象分配空間EFFrame* eff = new EFFrame(fh);eff->idx = frames.size();//將eff對象插入EFFrame類的frames的隊列中frames.push_back(eff);nFrames++;fh->efFrame = eff; //CPARSS是表示相機的四個內(nèi)參數(shù)吧 ,8 表示位姿加仿射,nFrames就是關鍵幀窗口中的幀數(shù)assert(HM.cols() == 8 * nFrames + CPARS-8);//顯然就是給舒爾消元矩陣分配空間呢啊bM.conservativeResize(8 * nFrames + CPARS);HM.conservativeResize(8 * nFrames + CPARS, 8 * nFrames + CPARS);//最新幀的最后8位置為0bM.tail<8>().setZero();////最后8列置為0HM.rightCols<8>().setZero();//最下面8行置為0HM.bottomRows<8>().setZero();EFIndicesValid = false;EFAdjointsValid=false;EFDeltaValid=false; //每次插入關鍵幀時計算。H T兩幀之間相對增量對二者絕對增量 //的偏導值,因為最終窗口優(yōu)化過程是計算各項的絕對增量值的偏導 //通過遍歷兩兩之間的關系,提前計算好adHostF和adTargetF //8*8的矩陣一共有64個。每兩幀之間都會有一個結果setAdjointsF(Hcalib);//新入隊的點加入優(yōu)化窗口的總點隊列里去makeIDX();for(EFFrame* fh2 : frames){connectivityMap[(((uint64_t)eff->frameID) << 32) + ((uint64_t)fh2->frameID)] = Eigen::Vector2i(0,0);if(fh2 != eff)connectivityMap[(((uint64_t)fh2->frameID) << 32) + ((uint64_t)eff->frameID)] = Eigen::Vector2i(0,0);} //返回創(chuàng)建的這個EFFrame類的對象return eff; } EFPoint* EnergyFunctional::insertPoint(PointHessian* ph) {EFPoint* efp = new EFPoint(ph, ph->host->efFrame);//idxInPoints 存的是efp->idxInPoints = ph->host->efFrame->points.size();//efp入隊ph->host->efFrame->points.push_back(efp);nPoints++;ph->efPoint = efp;EFIndicesValid = false;return efp; }void EnergyFunctional::dropResidual(EFResidual* r) {EFPoint* p = r->point;assert(r == p->residualsAll[r->idxInAll]);p->residualsAll[r->idxInAll] = p->residualsAll.back();p->residualsAll[r->idxInAll]->idxInAll = r->idxInAll;p->residualsAll.pop_back();if(r->isActive())r->host->data->shell->statistics_goodResOnThis++;elser->host->data->shell->statistics_outlierResOnThis++;connectivityMap[(((uint64_t)r->host->frameID) << 32) + ((uint64_t)r->target->frameID)][0]--;nResiduals--;r->data->efResidual=0;delete r; } void EnergyFunctional::marginalizeFrame(EFFrame* fh) {assert(EFDeltaValid);assert(EFAdjointsValid);assert(EFIndicesValid);assert((int)fh->points.size()==0);int ndim = nFrames*8+CPARS-8;// new dimensionint odim = nFrames*8+CPARS;// old dimension// VecX eigenvaluesPre = HM.eigenvalues().real(); // std::sort(eigenvaluesPre.data(), eigenvaluesPre.data()+eigenvaluesPre.size()); //if((int)fh->idx != (int)frames.size()-1){int io = fh->idx*8+CPARS; // index of frame to move to endint ntail = 8*(nFrames-fh->idx-1);assert((io+8+ntail) == nFrames*8+CPARS);Vec8 bTmp = bM.segment<8>(io);VecX tailTMP = bM.tail(ntail);bM.segment(io,ntail) = tailTMP;bM.tail<8>() = bTmp;MatXX HtmpCol = HM.block(0,io,odim,8);MatXX rightColsTmp = HM.rightCols(ntail);HM.block(0,io,odim,ntail) = rightColsTmp;HM.rightCols(8) = HtmpCol;MatXX HtmpRow = HM.block(io,0,8,odim);MatXX botRowsTmp = HM.bottomRows(ntail);HM.block(io,0,ntail,odim) = botRowsTmp;HM.bottomRows(8) = HtmpRow;}// // marginalize. First add prior here, instead of to active.HM.bottomRightCorner<8,8>().diagonal() += fh->prior;bM.tail<8>() += fh->prior.cwiseProduct(fh->delta_prior);// std::cout << std::setprecision(16) << "HMPre:\n" << HM << "\n\n";VecX SVec = (HM.diagonal().cwiseAbs()+VecX::Constant(HM.cols(), 10)).cwiseSqrt();VecX SVecI = SVec.cwiseInverse();// std::cout << std::setprecision(16) << "SVec: " << SVec.transpose() << "\n\n"; // std::cout << std::setprecision(16) << "SVecI: " << SVecI.transpose() << "\n\n";// scale!MatXX HMScaled = SVecI.asDiagonal() * HM * SVecI.asDiagonal();VecX bMScaled = SVecI.asDiagonal() * bM;// invert bottom part!Mat88 hpi = HMScaled.bottomRightCorner<8,8>();hpi = 0.5f*(hpi+hpi);hpi = hpi.inverse();hpi = 0.5f*(hpi+hpi);// schur-complement!MatXX bli = HMScaled.bottomLeftCorner(8,ndim).transpose() * hpi;HMScaled.topLeftCorner(ndim,ndim).noalias() -= bli * HMScaled.bottomLeftCorner(8,ndim);bMScaled.head(ndim).noalias() -= bli*bMScaled.tail<8>();//unscale!HMScaled = SVec.asDiagonal() * HMScaled * SVec.asDiagonal();bMScaled = SVec.asDiagonal() * bMScaled;// set.HM = 0.5*(HMScaled.topLeftCorner(ndim,ndim) + HMScaled.topLeftCorner(ndim,ndim).transpose());bM = bMScaled.head(ndim);// remove from vector, without changing the order!for(unsigned int i=fh->idx; i+1<frames.size();i++){frames[i] = frames[i+1];frames[i]->idx = i;}frames.pop_back();nFrames--;fh->data->efFrame=0;assert((int)frames.size()*8+CPARS == (int)HM.rows());assert((int)frames.size()*8+CPARS == (int)HM.cols());assert((int)frames.size()*8+CPARS == (int)bM.size());assert((int)frames.size() == (int)nFrames);// VecX eigenvaluesPost = HM.eigenvalues().real(); // std::sort(eigenvaluesPost.data(), eigenvaluesPost.data()+eigenvaluesPost.size());// std::cout << std::setprecision(16) << "HMPost:\n" << HM << "\n\n";// std::cout << "EigPre:: " << eigenvaluesPre.transpose() << "\n"; // std::cout << "EigPost: " << eigenvaluesPost.transpose() << "\n";EFIndicesValid = false;EFAdjointsValid=false;EFDeltaValid=false;makeIDX();delete fh; }void EnergyFunctional::marginalizePointsF() {assert(EFDeltaValid);assert(EFAdjointsValid);assert(EFIndicesValid);allPointsToMarg.clear();for(EFFrame* f : frames){for(int i=0;i<(int)f->points.size();i++){EFPoint* p = f->points[i];if(p->stateFlag == EFPointStatus::PS_MARGINALIZE){p->priorF *= setting_idepthFixPriorMargFac;for(EFResidual* r : p->residualsAll)if(r->isActive())connectivityMap[(((uint64_t)r->host->frameID) << 32) + ((uint64_t)r->target->frameID)][1]++;allPointsToMarg.push_back(p);}}}accSSE_bot->setZero(nFrames);accSSE_top_A->setZero(nFrames);for(EFPoint* p : allPointsToMarg){accSSE_top_A->addPoint<2>(p,this);accSSE_bot->addPoint(p,false);removePoint(p);}MatXX M, Msc;VecX Mb, Mbsc;accSSE_top_A->stitchDouble(M,Mb,this,false,false);accSSE_bot->stitchDouble(Msc,Mbsc,this);resInM+= accSSE_top_A->nres[0];MatXX H = M-Msc;VecX b = Mb-Mbsc;if(setting_solverMode & SOLVER_ORTHOGONALIZE_POINTMARG){// have a look if prior is there.bool haveFirstFrame = false;for(EFFrame* f : frames) if(f->frameID==0) haveFirstFrame=true;if(!haveFirstFrame)orthogonalize(&b, &H);}HM += setting_margWeightFac*H;bM += setting_margWeightFac*b;if(setting_solverMode & SOLVER_ORTHOGONALIZE_FULL){orthogonalize(&bM, &HM);}EFIndicesValid = false;makeIDX(); }void EnergyFunctional::dropPointsF() {for(EFFrame* f : frames){for(int i=0;i<(int)f->points.size();i++){EFPoint* p = f->points[i];if(p->stateFlag == EFPointStatus::PS_DROP){removePoint(p);i--;}}}EFIndicesValid = false;makeIDX(); }void EnergyFunctional::removePoint(EFPoint* p) {for(EFResidual* r : p->residualsAll)dropResidual(r);EFFrame* h = p->host;h->points[p->idxInPoints] = h->points.back();h->points[p->idxInPoints]->idxInPoints = p->idxInPoints;h->points.pop_back();nPoints--;p->data->efPoint = 0;EFIndicesValid = false;delete p; }void EnergyFunctional::orthogonalize(VecX* b, MatXX* H) { //決定對哪些空間進行正交化 // decide to which nullspaces to orthogonalize.std::vector<VecX> ns; //位姿零空間ns.insert(ns.end(), lastNullspaces_pose.begin(), lastNullspaces_pose.end()); //尺度零空間ns.insert(ns.end(), lastNullspaces_scale.begin(), lastNullspaces_scale.end());//構建零空間矩陣// make Nullspaces matrixMatXX N(ns[0].rows(), ns.size());for(unsigned int i = 0; i < ns.size(); i++)N.col(i) = ns[i].normalized();// compute Npi := N * (N' * N)^-1 = pseudo inverse of N.Eigen::JacobiSVD<MatXX> svdNN(N, Eigen::ComputeThinU | Eigen::ComputeThinV);VecX SNN = svdNN.singularValues();double minSv = 1e10, maxSv = 0;for(int i=0;i<SNN.size();i++){if(SNN[i] < minSv) minSv = SNN[i];if(SNN[i] > maxSv) maxSv = SNN[i];}for(int i = 0;i < SNN.size(); i++){ if(SNN[i] > setting_solverModeDelta*maxSv) SNN[i] = 1.0 / SNN[i]; else SNN[i] = 0; }MatXX Npi = svdNN.matrixU() * SNN.asDiagonal() * svdNN.matrixV().transpose(); // [dim] x 9.MatXX NNpiT = N*Npi.transpose(); // [dim] x [dim].MatXX NNpiTS = 0.5*(NNpiT + NNpiT.transpose()); // = N * (N' * N)^-1 * N'.//減去零空間部分得到正交化結果就是博客圖藍色小三角的位置吧if(b!=0) *b -= NNpiTS * *b;if(H!=0) *H -= NNpiTS * *H * NNpiTS;}//求解結果就是lastX 以及逆深度點的絕對增量值 //此結果中包含了相機位姿光度參數(shù)相機參數(shù)共4 + 8 * N(關鍵幀個數(shù)) //還包含了M個點的逆深度信息 ------------------------->的增量 void EnergyFunctional::solveSystemF(int iteration, double lambda, CalibHessian* HCalib) {if(setting_solverMode & SOLVER_USE_GN) lambda=0;if(setting_solverMode & SOLVER_FIX_LAMBDA) lambda = 1e-5;assert(EFDeltaValid);assert(EFAdjointsValid);assert(EFIndicesValid);MatXX HL_top, HA_top, H_sc;VecX bL_top, bA_top, bM_top, b_sc;//計算HA_top 矩陣內(nèi)容大小68*68 就是增量方程中的Hββ部分//bA_top是JTXr部分舒爾消元后方程組的第二行計算所需的參數(shù)//計算Hxx與Jxtr兩個值accumulateAF_MT(HA_top, bA_top,multiThreading);//這個函數(shù)沒啥用 因為里面的某個條件永遠得不到滿足accumulateLF_MT(HL_top, bL_top,multiThreading); //計算 schur部分參數(shù)存放在H_sc() b_sc()中 //舒爾消元后方程組的第二行計算所需的參數(shù) //最終得到的 Hsc 是 68x68 的矩陣,bsc 是 68x1 的矩陣。accumulateSCF_MT(H_sc, b_sc,multiThreading);bM_top = (bM+ HM * getStitchedDeltaF());MatXX HFinal_top;VecX bFinal_top;if(setting_solverMode & SOLVER_ORTHOGONALIZE_SYSTEM){//調試看不走這個分支// have a look if prior is there.bool haveFirstFrame = false;for(EFFrame* f : frames) if(f->frameID==0) haveFirstFrame=true;//對應公式MatXX HT_act = HL_top + HA_top - H_sc;VecX bT_act = bL_top + bA_top - b_sc;if(!haveFirstFrame)orthogonalize(&bT_act, &HT_act);HFinal_top = HT_act + HM;bFinal_top = bT_act + bM_top;lastHS = HFinal_top;lastbS = bFinal_top;for(int i=0;i<8*nFrames+CPARS;i++) HFinal_top(i,i) *= (1+lambda);}else{HFinal_top = HL_top + HM + HA_top;//后半部分是舒爾消元等式右下角值 bL_top是0bFinal_top = bL_top + bM_top + bA_top - b_sc;//這個是舒爾消元后等式左lastHS = HFinal_top - H_sc;//舒爾消元等式右lastbS = bFinal_top;for(int i = 0; i < 8 * nFrames + CPARS; i++) HFinal_top(i,i) *= (1 + lambda);HFinal_top -= H_sc * (1.0f/(1 + lambda));}VecX x;if(setting_solverMode & SOLVER_SVD){//調試看不走這個分支VecX SVecI = HFinal_top.diagonal().cwiseSqrt().cwiseInverse();MatXX HFinalScaled = SVecI.asDiagonal() * HFinal_top * SVecI.asDiagonal();VecX bFinalScaled = SVecI.asDiagonal() * bFinal_top;Eigen::JacobiSVD<MatXX> svd(HFinalScaled, Eigen::ComputeThinU | Eigen::ComputeThinV);VecX S = svd.singularValues();double minSv = 1e10, maxSv = 0;for(int i = 0; i < S.size(); i++){if(S[i] < minSv) minSv = S[i];if(S[i] > maxSv) maxSv = S[i];}VecX Ub = svd.matrixU().transpose()*bFinalScaled;int setZero=0;for(int i = 0;i < Ub.size(); i++){if(S[i] < setting_solverModeDelta*maxSv){ Ub[i] = 0; setZero++; }if((setting_solverMode & SOLVER_SVD_CUT7) && (i >= Ub.size()-7)){ Ub[i] = 0; setZero++; }else Ub[i] /= S[i];}x = SVecI.asDiagonal() * svd.matrixV() * Ub;}else{//std::cout<<"==="<<VecX::Constant(HFinal_top.cols(), 10)<<std::endl;//asDiagonal矩陣轉置 ldlt求解線性方程組 Ax = b cwiseSqrt 單個元素開方 cwiseInverse 1/單個元素 //Constant 常量矩陣值都為10VecX SVecI = (HFinal_top.diagonal()+VecX::Constant(HFinal_top.cols(), 10)).cwiseSqrt().cwiseInverse();MatXX HFinalScaled = SVecI.asDiagonal() * HFinal_top * SVecI.asDiagonal();x = SVecI.asDiagonal() * HFinalScaled.ldlt().solve(SVecI.asDiagonal() * bFinal_top);// SVec.asDiagonal() * svd.matrixV() * Ub;}if((setting_solverMode & SOLVER_ORTHOGONALIZE_X) || (iteration >= 2 && (setting_solverMode & SOLVER_ORTHOGONALIZE_X_LATER))){VecX xOld = x;//零空間 就當對位姿和尺度做了次修正吧 orthogonalize(&x, 0);} //這個應該是相機參數(shù) 位姿 仿射的絕對增量值lastX = x;currentLambda= lambda;//計算一次點的逆深度的絕對增量值resubstituteF_MT(x, HCalib,multiThreading);currentLambda=0;} // 來新幀的時候 就把frames中的所有幀的點重新排一次 void EnergyFunctional::makeIDX() { //重新將順序排一下frames中按序號0 ~ frames.size()來排號for(unsigned int idx=0;idx<frames.size();idx++)frames[idx]->idx = idx;//allPoints隊列清空 allPoints.clear();//遍歷frames 所有幀for(EFFrame* f : frames)for(EFPoint* p : f->points)//遍歷幀上的點{//重新對allPoints隊列賦值allPoints.push_back(p);//遍歷點的所有殘差for(EFResidual* r : p->residualsAll){//改變殘差的ID號r->hostIDX = r->host->idx;r->targetIDX = r->target->idx;}}EFIndicesValid=true; }VecX EnergyFunctional::getStitchedDeltaF() const {VecX d = VecX(CPARS+nFrames*8); d.head<CPARS>() = cDeltaF.cast<double>();for(int h=0;h<nFrames;h++) d.segment<8>(CPARS+8*h) = frames[h]->delta;return d; }} /** * This file is part of DSO. * * Copyright 2016 Technical University of Munich and Intel. * Developed by Jakob Engel <engelj at in dot tum dot de>, * for more information see <http://vision.in.tum.de/dso>. * If you use this code, please cite the respective publications as * listed on the above website. * * DSO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DSO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DSO. If not, see <http://www.gnu.org/licenses/>. */#include "OptimizationBackend/EnergyFunctionalStructs.h" #include "OptimizationBackend/EnergyFunctional.h" #include "FullSystem/FullSystem.h" #include "FullSystem/HessianBlocks.h" #include "FullSystem/Residuals.h"#if !defined(__SSE3__) && !defined(__SSE2__) && !defined(__SSE1__) #include "SSE2NEON.h" #endifnamespace dso {//博客4.7.6 列出 代表的實際意義很明確 void EFResidual::takeDataF() {std::swap<RawResidualJacobian*>(J, data->J);Vec2f JI_JI_Jd = J->JIdx2 * J->Jpdd;for(int i = 0; i < 6; i++)JpJdF[i] = J->Jpdxi[0][i] * JI_JI_Jd[0] + J->Jpdxi[1][i] * JI_JI_Jd[1]; //JpJdF 殘差對位姿的偏導的轉置* 殘差對逆深度的偏導JpJdF.segment<2>(6) = J->JabJIdx * J->Jpdd; }void EFFrame::takeData() {prior = data->getPrior().head<8>();delta = data->get_state_minus_stateZero().head<8>();delta_prior = (data->get_state() - data->getPriorZero()).head<8>();assert(data->frameID != -1);frameID = data->frameID; }void EFPoint::takeData() {priorF = data->hasDepthPrior ? setting_idepthFixPrior*SCALE_IDEPTH*SCALE_IDEPTH : 0;if(setting_solverMode & SOLVER_REMOVE_POSEPRIOR) priorF=0;deltaF = data->idepth-data->idepth_zero; }void EFResidual::fixLinearizationF(EnergyFunctional* ef1) {Vec8f dp = ef1->adHTdeltaF[hostIDX+ef1->nFrames*targetIDX];// compute Jp*delta__m128 Jp_delta_x = _mm_set1_ps(J->Jpdxi[0].dot(dp.head<6>())+J->Jpdc[0].dot(ef1->cDeltaF)+J->Jpdd[0]*point->deltaF);__m128 Jp_delta_y = _mm_set1_ps(J->Jpdxi[1].dot(dp.head<6>())+J->Jpdc[1].dot(ef1->cDeltaF)+J->Jpdd[1]*point->deltaF);__m128 delta_a = _mm_set1_ps((float)(dp[6]));__m128 delta_b = _mm_set1_ps((float)(dp[7]));for(int i=0;i<patternNum;i+=4){// PATTERN: rtz = resF - [JI*Jp Ja]*delta.__m128 rtz = _mm_load_ps(((float*)&J->resF)+i);rtz = _mm_sub_ps(rtz,_mm_mul_ps(_mm_load_ps(((float*)(J->JIdx))+i),Jp_delta_x));rtz = _mm_sub_ps(rtz,_mm_mul_ps(_mm_load_ps(((float*)(J->JIdx+1))+i),Jp_delta_y));rtz = _mm_sub_ps(rtz,_mm_mul_ps(_mm_load_ps(((float*)(J->JabF))+i),delta_a));rtz = _mm_sub_ps(rtz,_mm_mul_ps(_mm_load_ps(((float*)(J->JabF+1))+i),delta_b));_mm_store_ps(((float*)&res_toZeroF)+i, rtz);}isLinearized = true; }} /** * This file is part of DSO. * * Copyright 2016 Technical University of Munich and Intel. * Developed by Jakob Engel <engelj at in dot tum dot de>, * for more information see <http://vision.in.tum.de/dso>. * If you use this code, please cite the respective publications as * listed on the above website. * * DSO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DSO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DSO. If not, see <http://www.gnu.org/licenses/>. *//** KFBuffer.cpp** Created on: Jan 7, 2014* Author: engelj*/#include "FullSystem/FullSystem.h"#include "stdio.h" #include "util/globalFuncs.h" #include <Eigen/LU> #include <algorithm> #include "IOWrapper/ImageDisplay.h" #include "util/globalCalib.h"#include <Eigen/SVD> #include <Eigen/Eigenvalues> #include "FullSystem/ImmaturePoint.h" #include "math.h"namespace dso {//point是未成熟點,用優(yōu)化的方法算了次currentIdepth來更新未成熟點的 //一些深度相關的屬性 ,并算了下該點對應的殘差 PointHessian* FullSystem::optimizeImmaturePoint(ImmaturePoint* point, int minObs,ImmaturePointTemporaryResidual* residuals) { //外面創(chuàng)建了這么個結構體residuals 下面這段就開始對這個結構體賦值//未成熟點在非自身幀之外的幀投影的總個數(shù)int nres = 0; //遍歷關鍵幀窗口,每個未成熟點與其非所在的關鍵幀都有個殘差存在for(FrameHessian* fh : frameHessians){//點與非點所在幀計算殘差if(fh != point->host){residuals[nres].state_NewEnergy = residuals[nres].state_energy = 0;residuals[nres].state_NewState = ResState::OUTLIER;residuals[nres].state_state = ResState::IN;//非點所在幀residuals[nres].target = fh;nres++;}}assert(nres == ((int)frameHessians.size())-1);bool print = false;//rand()%50==0;float lastEnergy = 0;float lastHdd=0;float lastbd=0;float currentIdepth=(point->idepth_max + point->idepth_min) * 0.5f;//遍歷某個未成熟點計算一次殘差for(int i = 0; i < nres; i++){lastEnergy += point->linearizeResidual(&Hcalib, 1000, residuals + i,lastHdd, lastbd, currentIdepth);residuals[i].state_state = residuals[i].state_NewState;residuals[i].state_energy = residuals[i].state_NewEnergy;}if(!std::isfinite(lastEnergy) || lastHdd < setting_minIdepthH_act){if(print)printf("OptPoint: Not well-constrained (%d res, H=%.1f). E=%f. SKIP!\n",nres, lastHdd, lastEnergy);return 0;}if(print) printf("Activate point. %d residuals. H=%f. Initial Energy: %f. Initial Id=%f\n" ,nres, lastHdd,lastEnergy,currentIdepth);float lambda = 0.1;//高斯牛頓方法優(yōu)化 只有一個變量 就是idepthfor(int iteration = 0; iteration < setting_GNItsOnPointActivation; iteration++){float H = lastHdd;H *= 1 + lambda;//解方程 算得逆深度增量為stepfloat step = (1.0 / H) * lastbd;float newIdepth = currentIdepth - step;float newHdd = 0; float newbd = 0; float newEnergy = 0;for(int i = 0; i < nres; i++){//計算殘差主函數(shù)newEnergy += point->linearizeResidual(&Hcalib, 1, residuals + i, newHdd, newbd, newIdepth);}if(!std::isfinite(lastEnergy) || newHdd < setting_minIdepthH_act){if(print) printf("OptPoint: Not well-constrained (%d res, H=%.1f). E=%f. SKIP!\n",nres,newHdd,lastEnergy);return 0;}if(print) printf("%s %d (L %.2f) %s: %f -> %f (idepth %f)!\n",(true || newEnergy < lastEnergy) ? "ACCEPT" : "REJECT",iteration,log10(lambda),"",lastEnergy, newEnergy, newIdepth);//新的優(yōu)化結果可接受 更新state_state state_energyif(newEnergy < lastEnergy){currentIdepth = newIdepth;lastHdd = newHdd;lastbd = newbd;lastEnergy = newEnergy;for(int i=0;i<nres;i++){residuals[i].state_state = residuals[i].state_NewState;residuals[i].state_energy = residuals[i].state_NewEnergy;}lambda *= 0.5;}else{lambda *= 5;}if(fabsf(step) < 0.0001*currentIdepth)break;}if(!std::isfinite(currentIdepth)){printf("MAJOR ERROR! point idepth is nan after initialization (%f).\n", currentIdepth);return (PointHessian*)((long)(-1)); // yeah I'm like 99% sure this is OK on 32bit systems.}//符合條件的點太少了int numGoodRes = 0;for(int i=0;i<nres;i++)if(residuals[i].state_state == ResState::IN) numGoodRes++;if(numGoodRes < minObs){if(print) printf("OptPoint: OUTLIER!\n");return (PointHessian*)((long)(-1)); // yeah I'm like 99% sure this is OK on 32bit systems.}//更新成熟點的深度信息 //新建一個PointHessian點p。下面是對這個點內(nèi)容各種賦值 //包括逆深度 點相對其他關鍵幀的殘差等等PointHessian* p = new PointHessian(point, &Hcalib);if(!std::isfinite(p->energyTH)) {delete p; return (PointHessian*)((long)(-1));}p->lastResiduals[0].first = 0;p->lastResiduals[0].second = ResState::OOB;p->lastResiduals[1].first = 0;p->lastResiduals[1].second = ResState::OOB;//currentIdepth是上面算出來的p->setIdepthZero(currentIdepth);p->setIdepth(currentIdepth);p->setPointStatus(PointHessian::ACTIVE); //初始化該點相對除自己所在幀的每幀的殘差數(shù)據(jù)rfor(int i = 0; i < nres; i++)if(residuals[i].state_state == ResState::IN){PointFrameResidual* r = new PointFrameResidual(p, p->host, residuals[i].target);r->state_NewEnergy = r->state_energy = 0;r->state_NewState = ResState::OUTLIER;//給屬性state_state賦值為ResState::INr->setState(ResState::IN);//p對應的殘差入隊p->residuals.push_back(r);if(r->target == frameHessians.back()){p->lastResiduals[0].first = r;p->lastResiduals[0].second = ResState::IN;}else if(r->target == (frameHessians.size()<2 ? 0 : frameHessians[frameHessians.size()-2])){p->lastResiduals[1].first = r;p->lastResiduals[1].second = ResState::IN;}}if(print) printf("point activated!\n");statistics_numActivatedPoints++;return p; }} /** * This file is part of DSO. * * Copyright 2016 Technical University of Munich and Intel. * Developed by Jakob Engel <engelj at in dot tum dot de>, * for more information see <http://vision.in.tum.de/dso>. * If you use this code, please cite the respective publications as * listed on the above website. * * DSO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DSO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DSO. If not, see <http://www.gnu.org/licenses/>. */#pragma once #define MAX_ACTIVE_FRAMES 100#include "util/globalCalib.h" #include "vector"#include <iostream> #include <fstream> #include "util/NumType.h" #include "FullSystem/Residuals.h" #include "util/ImageAndExposure.h"namespace dso {inline Vec2 affFromTo(const Vec2 &from, const Vec2 &to) // contains affine parameters as XtoWorld. {return Vec2(from[0] / to[0], (from[1] - to[1]) / to[0]); }struct FrameHessian; struct PointHessian;class ImmaturePoint; class FrameShell;class EFFrame; class EFPoint;#define SCALE_IDEPTH 1.0f // scales internal value to idepth. #define SCALE_XI_ROT 1.0f #define SCALE_XI_TRANS 0.5f #define SCALE_F 50.0f #define SCALE_C 50.0f #define SCALE_W 1.0f #define SCALE_A 10.0f #define SCALE_B 1000.0f#define SCALE_IDEPTH_INVERSE (1.0f / SCALE_IDEPTH) #define SCALE_XI_ROT_INVERSE (1.0f / SCALE_XI_ROT) #define SCALE_XI_TRANS_INVERSE (1.0f / SCALE_XI_TRANS) #define SCALE_F_INVERSE (1.0f / SCALE_F) #define SCALE_C_INVERSE (1.0f / SCALE_C) #define SCALE_W_INVERSE (1.0f / SCALE_W) #define SCALE_A_INVERSE (1.0f / SCALE_A) #define SCALE_B_INVERSE (1.0f / SCALE_B)struct FrameFramePrecalc {EIGEN_MAKE_ALIGNED_OPERATOR_NEW;// static valuesstatic int instanceCounter;FrameHessian* host; // defines row 定義行FrameHessian* target; // defines column定義列// precalc values預測值Mat33f PRE_RTll;//對應郭瑞瑞的Mat33f PRE_KRKiTll;Mat33f PRE_RKiTll;Mat33f PRE_RTll_0;Vec2f PRE_aff_mode;float PRE_b0_mode;Vec3f PRE_tTll;Vec3f PRE_KtTll;Vec3f PRE_tTll_0;float distanceLL;inline ~FrameFramePrecalc() {}inline FrameFramePrecalc() {host=target=0;}void set(FrameHessian* host, FrameHessian* target, CalibHessian* HCalib); };//關鍵幀 單幀結構struct FrameHessian {EIGEN_MAKE_ALIGNED_OPERATOR_NEW;EFFrame* efFrame;//// constant info & pre-calculated values//DepthImageWrap* frame;FrameShell* shell; isOOB//跟蹤,精細跟蹤。 用于方向選擇(不適用于梯度直方圖等)Eigen::Vector3f* dI; // trace, fine tracking. Used for direction select (not for gradient histograms etc.)Eigen::Vector3f* dIp[PYR_LEVELS]; // coarse tracking / coarse initializer. NAN in [0] only.float* absSquaredGrad[PYR_LEVELS]; // only used for pixel select (histograms etc.). no NAN.//關鍵幀歷史隊列的中幀的編號,int frameID; // incremental ID for keyframes only!static int instanceCounter;//關鍵幀窗口隊列中幀的編號int idx;// Photometric Calibration Stuff光度校準材料float frameEnergyTH; // set dynamically depending on tracking residual根據(jù)跟蹤殘差動態(tài)設置float ab_exposure;bool flaggedForMarginalization; //是所有活躍點的信息。所謂活躍點,是指它們在相機的視野中, //其殘差項仍在參與優(yōu)化部分的計算;就是成熟點std::vector<PointHessian*> pointHessians; // contains all ACTIVE points.包含所有ACTIVE點。//是已經(jīng)邊緣化的地圖點。std::vector<PointHessian*> pointHessiansMarginalized; // contains all MARGINALIZED points (= fully marginalized, usually because point went OOB.) //是被判為外點(outlier)的地圖點std::vector<PointHessian*> pointHessiansOut; // contains all OUTLIER points (= discarded.).包含所有OUTLIER點(=丟棄。)。 //為未成熟地圖點的信息std::vector<ImmaturePoint*> immaturePoints; // contains all OUTLIER points (= discarded.).Mat66 nullspaces_pose;Mat42 nullspaces_affine;Vec6 nullspaces_scale;// variable info.SE3 worldToCam_evalPT;//Vec10 state_zero;Vec10 state_scaled;//世界到相機的位姿變換+ 光度仿射變換 (前 8位的內(nèi)容)// [0-5: worldToCam-leftEps. 6-7: a,b]Vec10 state; Vec10 step;Vec10 step_backup;Vec10 state_backup;EIGEN_STRONG_INLINE const SE3 &get_worldToCam_evalPT() const {return worldToCam_evalPT;}EIGEN_STRONG_INLINE const Vec10 &get_state_zero() const {return state_zero;}EIGEN_STRONG_INLINE const Vec10 &get_state() const {return state;}EIGEN_STRONG_INLINE const Vec10 &get_state_scaled() const {return state_scaled;}EIGEN_STRONG_INLINE const Vec10 get_state_minus_stateZero() const {return get_state() - get_state_zero();}// precalc values 預測值SE3 PRE_worldToCam;SE3 PRE_camToWorld;std::vector<FrameFramePrecalc,Eigen::aligned_allocator<FrameFramePrecalc>> targetPrecalc;MinimalImageB3* debugImage;inline Vec6 w2c_leftEps() const {return get_state_scaled().head<6>();}inline AffLight aff_g2l() const {return AffLight(get_state_scaled()[6], get_state_scaled()[7]);}inline AffLight aff_g2l_0() const {return AffLight(get_state_zero()[6]*SCALE_A, get_state_zero()[7]*SCALE_B);}void setStateZero(const Vec10 &state_zero1);inline void setState(const Vec10 &state0){this->state = state0;state_scaled.segment<3>(0) = SCALE_XI_TRANS * state0.segment<3>(0);state_scaled.segment<3>(3) = SCALE_XI_ROT * state0.segment<3>(3);state_scaled[6] = SCALE_A * state0[6];state_scaled[7] = SCALE_B * state0[7];state_scaled[8] = SCALE_A * state0[8];state_scaled[9] = SCALE_B * state0[9];//w2c_leftEps返回的是state_scaled。PRE_worldToCam = SE3::exp(w2c_leftEps()) * get_worldToCam_evalPT();PRE_camToWorld = PRE_worldToCam.inverse();//setCurrentNullspace();};inline void setStateScaled(const Vec10 &state_scaled0){this->state_scaled = state_scaled0;state.segment<3>(0) = SCALE_XI_TRANS_INVERSE * state_scaled0.segment<3>(0);//0 1 2state.segment<3>(3) = SCALE_XI_ROT_INVERSE * state_scaled0.segment<3>(3);// 3 4 5state[6] = SCALE_A_INVERSE * state_scaled0[6];state[7] = SCALE_B_INVERSE * state_scaled0[7];state[8] = SCALE_A_INVERSE * state_scaled0[8];state[9] = SCALE_B_INVERSE * state_scaled0[9]; //PRE_worldToCam 預測的世界到相機的位姿變換//w2c_leftEps返回的是state_scaled的前6個數(shù) 而在上面state_scaled0對其賦值了,而//state_scaled0又恰好前6個是0啊。所以PRE_worldToCam就是沒變化啊 ------看代碼分析PRE_worldToCam = SE3::exp(w2c_leftEps()) * get_worldToCam_evalPT(); //世界到相機//下面那個就是預測的相機到世界的位姿變換了PRE_camToWorld = PRE_worldToCam.inverse();//相機到世界//setCurrentNullspace();};//* 設置當前位姿, 和狀態(tài)增量, 同時設置了FEJ點// 這個是優(yōu)化函數(shù)內(nèi)部用的真正改變狀態(tài)變量的地方inline void setEvalPT(const SE3 &worldToCam_evalPT0, const Vec10 &state0){this->worldToCam_evalPT = worldToCam_evalPT0;setState(state0);//給setStateZero賦值的地方setStateZero(state0);};//設置當前位姿, 光度仿射系數(shù) 這個是初始化用的 在執(zhí)行一些操作之前賦值inline void setEvalPT_scaled(const SE3 &worldToCam_evalPT0, const AffLight &aff_g2l){Vec10 initial_state = Vec10::Zero();// 直接設置光度系數(shù)a和binitial_state[6] = aff_g2l.a;initial_state[7] = aff_g2l.b;//世界到相機的位姿變換this->worldToCam_evalPT = worldToCam_evalPT0;//修改過PRE_worldToCam和另一個的值//initial_state關于位姿的值為0setStateScaled(initial_state); //給setStateZero賦值的地方setStateZero(this->get_state());//this->get_state()就是返回state };void release();inline ~FrameHessian(){assert(efFrame==0);release(); instanceCounter--;for(int i=0;i<pyrLevelsUsed;i++){delete[] dIp[i];delete[] absSquaredGrad[i];}if(debugImage != 0) delete debugImage;};inline FrameHessian(){instanceCounter++;flaggedForMarginalization=false;frameID = -1;efFrame = 0;frameEnergyTH = 8*8*patternNum;debugImage=0;};void makeImages(float* color, CalibHessian* HCalib);inline Vec10 getPrior(){Vec10 p = Vec10::Zero();if(frameID==0){p.head<3>() = Vec3::Constant(setting_initialTransPrior);p.segment<3>(3) = Vec3::Constant(setting_initialRotPrior);if(setting_solverMode & SOLVER_REMOVE_POSEPRIOR) p.head<6>().setZero();p[6] = setting_initialAffAPrior;p[7] = setting_initialAffBPrior;}else{if(setting_affineOptModeA < 0)p[6] = setting_initialAffAPrior;elsep[6] = setting_affineOptModeA;if(setting_affineOptModeB < 0)p[7] = setting_initialAffBPrior;elsep[7] = setting_affineOptModeB;}p[8] = setting_initialAffAPrior;p[9] = setting_initialAffBPrior;return p;}inline Vec10 getPriorZero(){return Vec10::Zero();}};struct CalibHessian {EIGEN_MAKE_ALIGNED_OPERATOR_NEW;static int instanceCounter;VecC value_zero;VecC value_scaled;VecCf value_scaledf;VecCf value_scaledi;VecC value;VecC step;VecC step_backup;VecC value_backup;VecC value_minus_value_zero;inline ~CalibHessian() {instanceCounter--;}inline CalibHessian(){VecC initial_value = VecC::Zero();initial_value[0] = fxG[0];initial_value[1] = fyG[0];initial_value[2] = cxG[0];initial_value[3] = cyG[0];setValueScaled(initial_value);value_zero = value;value_minus_value_zero.setZero();instanceCounter++;for(int i=0;i<256;i++)Binv[i] = B[i] = i; // set gamma function to identity};// normal mode: use the optimized parameters everywhere!inline float& fxl() {return value_scaledf[0];}inline float& fyl() {return value_scaledf[1];}inline float& cxl() {return value_scaledf[2];}inline float& cyl() {return value_scaledf[3];}inline float& fxli() {return value_scaledi[0];}inline float& fyli() {return value_scaledi[1];}inline float& cxli() {return value_scaledi[2];}inline float& cyli() {return value_scaledi[3];}inline void setValue(const VecC &value){// [0-3: Kl, 4-7: Kr, 8-12: l2r]this->value = value;value_scaled[0] = SCALE_F * value[0];value_scaled[1] = SCALE_F * value[1];value_scaled[2] = SCALE_C * value[2];value_scaled[3] = SCALE_C * value[3];this->value_scaledf = this->value_scaled.cast<float>();this->value_scaledi[0] = 1.0f / this->value_scaledf[0];this->value_scaledi[1] = 1.0f / this->value_scaledf[1];this->value_scaledi[2] = - this->value_scaledf[2] / this->value_scaledf[0];this->value_scaledi[3] = - this->value_scaledf[3] / this->value_scaledf[1];this->value_minus_value_zero = this->value - this->value_zero;};inline void setValueScaled(const VecC &value_scaled){this->value_scaled = value_scaled;this->value_scaledf = this->value_scaled.cast<float>();value[0] = SCALE_F_INVERSE * value_scaled[0];value[1] = SCALE_F_INVERSE * value_scaled[1];value[2] = SCALE_C_INVERSE * value_scaled[2];value[3] = SCALE_C_INVERSE * value_scaled[3];this->value_minus_value_zero = this->value - this->value_zero;this->value_scaledi[0] = 1.0f / this->value_scaledf[0];this->value_scaledi[1] = 1.0f / this->value_scaledf[1];this->value_scaledi[2] = - this->value_scaledf[2] / this->value_scaledf[0];this->value_scaledi[3] = - this->value_scaledf[3] / this->value_scaledf[1];};float Binv[256];float B[256];EIGEN_STRONG_INLINE float getBGradOnly(float color){int c = color+0.5f;if(c<5) c=5;if(c>250) c=250;return B[c+1]-B[c];}EIGEN_STRONG_INLINE float getBInvGradOnly(float color){int c = color+0.5f;if(c<5) c=5;if(c>250) c=250;return Binv[c+1]-Binv[c];} };// hessian component associated with one point. //與一點相關的hession 分量 struct PointHessian {EIGEN_MAKE_ALIGNED_OPERATOR_NEW;static int instanceCounter;EFPoint* efPoint;// static valuesfloat color[MAX_RES_PER_POINT]; // colors in host framefloat weights[MAX_RES_PER_POINT]; // host-weights for respective residuals.float u,v;int idx;float energyTH;FrameHessian* host;//幀bool hasDepthPrior;float my_type;float idepth_scaled;//inverse depth of point.float idepth_zero_scaled;float idepth_zero;float idepth;//深度增量值吧應該是float step;float step_backup;float idepth_backup;float nullspaces_scale;float idepth_hessian;float maxRelBaseline;int numGoodResiduals;enum PtStatus {ACTIVE=0, INACTIVE, OUTLIER, OOB, MARGINALIZED};PtStatus status;inline void setPointStatus(PtStatus s) {status=s;}inline void setIdepth(float idepth) {this->idepth = idepth;this->idepth_scaled = SCALE_IDEPTH * idepth;}inline void setIdepthScaled(float idepth_scaled) {this->idepth = SCALE_IDEPTH_INVERSE * idepth_scaled;this->idepth_scaled = idepth_scaled;}inline void setIdepthZero(float idepth) {idepth_zero = idepth;idepth_zero_scaled = SCALE_IDEPTH * idepth;nullspaces_scale = -(idepth*1.001 - idepth/1.001)*500;} //僅包含良好的殘差(不是OOB與OUTLIER)。 任意順序。std::vector<PointFrameResidual*> residuals; // only contains good residuals (not OOB and not OUTLIER). Arbitrary order. //包含有關最后兩個幀的殘差的信息。 ([0] =最新,[1] =前一個)。std::pair<PointFrameResidual*, ResState> lastResiduals[2]; // contains information about residuals to the last two (!) frames. ([0] = latest, [1] = the one before).void release();PointHessian(const ImmaturePoint* const rawPoint, CalibHessian* Hcalib);inline ~PointHessian() {assert(efPoint==0); release(); instanceCounter--;}inline bool isOOB(const std::vector<FrameHessian*>& toKeep, const std::vector<FrameHessian*>& toMarg) const{int visInToMarg = 0;for(PointFrameResidual* r : residuals){if(r->state_state != ResState::IN) continue;for(FrameHessian* k : toMarg)if(r->target == k) visInToMarg++;}if((int)residuals.size() >= setting_minGoodActiveResForMarg &&numGoodResiduals > setting_minGoodResForMarg+10 &&(int)residuals.size()-visInToMarg < setting_minGoodActiveResForMarg)return true;if(lastResiduals[0].second == ResState::OOB) return true;if(residuals.size() < 2) return false;if(lastResiduals[0].second == ResState::OUTLIER && lastResiduals[1].second == ResState::OUTLIER) return true;return false;}inline bool isInlierNew(){return (int)residuals.size() >= setting_minGoodActiveResForMarg&& numGoodResiduals >= setting_minGoodResForMarg;}};} /** * This file is part of DSO. * * Copyright 2016 Technical University of Munich and Intel. * Developed by Jakob Engel <engelj at in dot tum dot de>, * for more information see <http://vision.in.tum.de/dso>. * If you use this code, please cite the respective publications as * listed on the above website. * * DSO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DSO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DSO. If not, see <http://www.gnu.org/licenses/>. */#pragma once#include "util/NumType.h"namespace dso { //下面這個結構體這些分量 都在linearize函數(shù)中求得 struct RawResidualJacobian//原始殘余雅可比 {EIGEN_MAKE_ALIGNED_OPERATOR_NEW;// ================== new structure: save independently =============.VecNRf resF;//1個點對應的8個鄰域點的殘差值// the two rows of d[x,y]/d[xi].//位姿雅克比矩陣 ==像素坐標對相對位姿求偏導Vec6f Jpdxi[2]; // 2x6 // the two rows of d[x,y]/d[C].// ==像素坐標對相機相對內(nèi)參求導VecCf Jpdc[2]; // 2x4// the two rows of d[x,y]/d[idepth].//逆深度雅克比矩陣 ==像素坐標對host幀的逆深度求導Vec2f Jpdd; // 2x1// the two columns of d[r]/d[x,y]. ==殘差對target幀上的像素坐標求導 8個點VecNRf JIdx[2]; // 8x2// = the two columns of d[r] / d[ab] ==殘差對a21 b21求導 就是對光度系數(shù)增量求導數(shù)8個點VecNRf JabF[2]; // 8x2// = JIdx^T * JIdx (inner product). Only as a shorthand. 寫的很清晰Mat22f JIdx2; // 2x2// = Jab^T * JIdx (inner product). Only as a shorthand.Mat22f JabJIdx; // 2x2// = Jab^T * Jab (inner product). Only as a shorthand.Mat22f Jab2; // 2x2}; }

?

?

?

?

?

?

?

?

?

?

總結

以上是生活随笔為你收集整理的DSO窗口优化部分代码注释加理论解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

国产三级久久久 | 亚洲激情 欧美激情 | 久色网 | 高清在线观看av | 日韩在线视频网站 | 久久草视频 | 国产欧美在线一区二区三区 | 欧美精品中文字幕亚洲专区 | 中文字幕在线免费观看视频 | 狠狠色综合欧美激情 | 日韩在线观看 | 福利一区二区在线 | 国产香蕉久久精品综合网 | 婷婷久久网 | 久久免费电影网 | 欧美夫妻生活视频 | 亚洲最新视频在线 | 91久久精品一区二区三区 | 97超碰国产精品女人人人爽 | 国产精品久久久久久久久久久久午 | 97日日碰人人模人人澡分享吧 | 国产精品国产三级国产aⅴ入口 | 久久尤物电影视频在线观看 | 手机成人在线 | 91tv国产成人福利 | 在线视频一区观看 | 久久精品这里都是精品 | 中文亚洲欧美日韩 | 国产福利一区二区三区视频 | 精品在线免费视频 | 精品久久久精品 | 99热精品久久 | 在线亚洲小视频 | 久久久久9999亚洲精品 | 在线观看av的网站 | 亚洲综合欧美激情 | 日日夜av| 国产日韩欧美视频在线观看 | 波多野结衣理论片 | 亚洲a成人v | 日韩视 | 免费在线一区二区三区 | 五月婷婷综合激情 | 日日碰狠狠添天天爽超碰97久久 | 精品播放 | 97色涩| 久久久久电影 | 久草免费在线视频观看 | 亚洲日日日 | 玖玖视频国产 | 日日夜夜免费精品视频 | 7777精品伊人久久久大香线蕉 | 亚洲国产视频a | 丁香婷婷色综合亚洲电影 | 欧美成人tv | 国产精品亚洲人在线观看 | 亚洲午夜剧场 | 综合色中文 | 色99网| 亚洲综合丁香 | 成片免费观看视频999 | 亚洲成人欧美 | 欧美激情视频免费看 | 国产一区二区日本 | 成人xxxx| 婷婷综合伊人 | 在线一二区 | 色婷婷狠狠操 | 99久久99久久 | 波多野结衣精品视频 | 国色天香在线观看 | 久久av在线 | 夜夜躁日日躁狠狠久久av | 91热精品 | 在线观看完整版 | 狠狠久久伊人 | а中文在线天堂 | 日韩高清在线一区二区三区 | 日韩欧美在线免费观看 | 五月婷婷导航 | 国产精品色 | 国产精品入口久久 | 激情网站五月天 | 精品免费国产一区二区三区四区 | 午夜精品中文字幕 | www.久久成人 | 天天操天天添天天吹 | 久久人人爽人人爽人人片 | 91看片在线观看 | 国产福利在线不卡 | 亚洲人在线7777777精品 | 视频一区亚洲 | 日躁夜躁狠狠躁2001 | 99成人在线视频 | 久久99网站 | 麻花豆传媒mv在线观看 | 亚洲精品午夜一区人人爽 | 在线观看亚洲国产 | 精品91视频 | 国产污视频在线观看 | 国产精品成人aaaaa网站 | 天天亚洲 | 最近字幕在线观看第一季 | 超碰av在线播放 | 欧美日韩一区二区免费在线观看 | 在线观看日韩视频 | 免费中文字幕在线观看 | 日韩精品不卡在线观看 | 亚洲五月婷| 亚洲视频免费视频 | 视频一区二区免费 | 黄色一区二区在线观看 | 久草热视频 | av成人在线网站 | 夜夜躁日日躁 | 国产精品国产三级国产aⅴ无密码 | 日韩在线视频国产 | av在线不卡观看 | 99久久久久久久 | 欧美一区免费在线观看 | 黄色录像av | 国产福利a| av色综合| 九九免费精品 | 一区二区三区电影 | 久久久久欠精品国产毛片国产毛生 | 亚洲精品观看 | 亚洲aⅴ乱码精品成人区 | 91视频免费 | 日本久久精品 | 91免费观看网站 | 涩五月婷婷 | 91精品国产99久久久久久红楼 | 麻豆精品传媒视频 | 在线观看av中文字幕 | 三级av免费观看 | 中文字幕中文字幕在线中文字幕三区 | 日韩av电影中文字幕在线观看 | 国产夫妻性生活自拍 | 亚洲精品国产成人av在线 | 中文字幕免费成人 | 国产男女免费完整视频 | 精品亚洲欧美一区 | 久久久国产精品免费 | 在线视频观看91 | 欧美日韩大片在线观看 | 精品一区二区免费视频 | 免费在线中文字幕 | 免费观看一级一片 | 久久久久国产视频 | 激情综合网五月 | 黄色一级免费电影 | 午夜a区| 午夜丁香视频在线观看 | 欧美色图另类 | 天天干天天草 | 亚洲欧洲精品久久 | 黄色小视频在线观看免费 | 国产高清视频网 | 中国精品一区二区 | 日韩亚洲国产精品 | 99午夜| 香蕉日日| 日韩特级黄色片 | 久久不卡日韩美女 | 国产成人精品午夜在线播放 | 国产五月色婷婷六月丁香视频 | 日韩高清成人 | 综合久久精品 | 日韩专区一区二区 | 亚洲情影院 | 日韩激情久久 | 91在线色 | 中文字幕在线观看免费观看 | 男女精品久久 | 91高清视频 | 亚洲精品成人av在线 | 91粉色视频 | 91在线免费公开视频 | 日韩精品一区二区三区免费视频观看 | 中文字幕在线看视频国产中文版 | 国产精品麻豆一区二区三区 | 成人全视频免费观看在线看 | aaa毛片视频 | 欧美精品久久久久久久免费 | 午夜精品电影 | 久久刺激视频 | 亚洲爱视频 | 国产视频 亚洲精品 | 精品国产区在线 | 亚洲 欧美变态 另类 综合 | 免费91在线 | 国产日韩中文字幕在线 | 中文字幕超清在线免费 | 欧美日韩精品免费观看 | 久久精品96 | 亚洲精品视频在线观看免费视频 | 日本在线成人 | 国产精品一区二区三区免费视频 | 91麻豆精品国产午夜天堂 | 91视频麻豆视频 | 色偷偷97| 久久理论影院 | 国产精品午夜久久 | 狠狠色狠狠色综合日日小说 | 天天操天天能 | 精品国产伦一区二区三区观看方式 | 成人影片免费 | 五月激情姐姐 | 一本色道久久综合亚洲二区三区 | 波多野结衣在线视频一区 | 免费在线成人 | 日本视频高清 | 国产美女黄网站免费 | 西西人体4444www高清视频 | 免费久久视频 | 色婷婷综合久久久久中文字幕1 | 亚洲高清视频在线播放 | 美女黄视频免费看 | 99av在线视频 | 麻豆免费视频网站 | 国产高清精品在线观看 | 极品久久久久 | 91看片淫黄大片91 | 亚洲欧洲中文日韩久久av乱码 | 久久久国产精品麻豆 | 91自拍成人 | 免费h漫在线观看 | 国产精品综合在线观看 | 天天碰天天操视频 | 国产高清视频色在线www | 99热这里精品 | 婷婷丁香激情综合 | 亚洲精品美女 | 久久爱综合 | 久久污视频 | av电影中文字幕在线观看 | 欧美日韩中文字幕在线视频 | av黄色免费在线观看 | 国产在线久久久 | 成人av播放 | 天天综合网天天 | 日韩av电影网站在线观看 | 精品 一区 在线 | 亚洲aⅴ在线观看 | 久久久99精品免费观看app | 国产69久久久欧美一级 | 成年人黄色免费看 | 亚洲精品乱码白浆高清久久久久久 | www日韩| 成人黄在线 | 中文字幕观看在线 | 亚洲日本激情 | 视频国产一区二区三区 | av不卡中文字幕 | 国产福利网站 | 亚洲综合激情 | 中日韩男男gay无套 日韩精品一区二区三区高清免费 | 欧美一级性生活视频 | 色综合久久综合网 | 丁香激情综合久久伊人久久 | 国产伦理久久精品久久久久_ | 亚洲精品字幕在线 | 最近的中文字幕大全免费版 | 精品免费在线视频 | 久久9999久久 | 中文国产成人精品久久一 | 国产成人免费精品 | 久久久久成人免费 | 日韩午夜在线播放 | 黄色视屏在线免费观看 | 久影院| 91秒拍国产福利一区 | 日韩在线免费小视频 | av综合站 | 国产69熟| 久久婷婷视频 | 免费在线观看av的网站 | 色综合天天射 | 亚洲国产免费网站 | 国产午夜激情视频 | 在线观看成人网 | 国产高清久久久久 | 黄色三级网站在线观看 | 天堂av在线| ,午夜性刺激免费看视频 | 蜜臀久久99静品久久久久久 | 99久久99精品 | 色婷婷播放| 日韩欧美一区二区三区免费观看 | 欧美国产在线看 | 狠狠干免费 | 日韩中文字幕视频在线 | 成人9ⅰ免费影视网站 | 亚洲精品女 | 国产精品伦一区二区三区视频 | 免费日韩一区二区三区 | 911精品视频 | 91麻豆视频 | 天天插狠狠插 | 99热精品国产一区二区在线观看 | 国产黄色片在线免费观看 | 在线观看av免费 | 国产精品 日韩 欧美 | 国产一级片免费播放 | 久久久久久久久影院 | 亚洲欧美在线观看视频 | 在线免费高清 | 国产一区免费在线观看 | 中文字幕在线免费 | 伊人天天狠天天添日日拍 | 午夜国产一区二区 | 超碰97人人干 | 国产精品免费人成网站 | 欧美一级专区免费大片 | 西西444www | 亚洲天堂社区 | 国产成人精品一区二区三区福利 | 中文一区在线 | 亚洲精品视频在线播放 | 久久成| 91看片在线看片 | 国产中文字幕视频在线 | 婷婷色社区 | 色99之美女主播在线视频 | 久久国产高清 | 精品在线播放 | 91av短视频| 99精品国产免费久久 | 欧美久久久久久久久久久久久 | 99 色 | 综合色爱 | 国产成人精品一区一区一区 | 五月视频 | 亚洲丝袜一区二区 | 天天透天天插 | 午夜私人影院 | 黄色av免费看 | 久久成人国产精品免费软件 | 97超碰人| 人人擦 | 国产精品久久久久久影院 | 狠狠狠色丁香婷婷综合久久88 | 久久久久久久久久毛片 | 97超视频在线观看 | 午夜18视频在线观看 | av丝袜美腿 | 久草视频在线免费播放 | 五月婷在线播放 | 天天射天天操天天色 | 网站免费黄色 | 日本中文一区二区 | 久久精品国产久精国产 | 波多野结衣精品在线 | 操久在线 | 国产视频丨精品|在线观看 国产精品久久久久久久久久久久午夜 | 国精产品永久999 | 久久久这里有精品 | 最近的中文字幕大全免费版 | 中文字幕免费观看视频 | 免费在线观看黄 | 特黄特色特刺激视频免费播放 | 五月开心六月婷婷 | 国产精品综合在线观看 | 免费福利在线视频 | 高清av中文在线字幕观看1 | 96精品高清视频在线观看软件特色 | 97福利 | 精品久久久久久久久久国产 | 日女人电影 | 国产视频精品网 | 色精品视频 | 色综合久久88色综合天天6 | 麻豆一二三精选视频 | 婷婷在线不卡 | 最新日韩在线观看视频 | 91热爆在线观看 | 日本aaaa级毛片在线看 | 欧美在线视频一区二区三区 | 亚洲高清不卡av | 日韩电影在线一区二区 | 欧美成人理伦片 | 国产夫妻性生活自拍 | se视频网址 | 国产一区国产二区在线观看 | 一级电影免费在线观看 | 国产一级免费在线 | 91精品视频在线观看免费 | 精品久久久久久综合日本 | 国产精品免费久久久久 | 成年人国产在线观看 | 成人福利在线观看 | 国产又粗又猛又爽又黄的视频先 | 日韩一区二区免费视频 | 亚洲资源在线观看 | 国产福利91精品一区二区三区 | 国产片免费在线观看视频 | 国产成人av免费在线观看 | 蜜臀av免费一区二区三区 | 激情丁香在线 | 日韩欧美在线视频一区二区 | 日韩大片免费观看 | 欧美在线观看禁18 | 国产亚洲精品精品精品 | 五月天.com | a久久免费视频 | 中文字幕大全 | 久久理论电影 | 久草电影在线观看 | 人成午夜视频 | 国产日韩欧美在线 | 91在线操 | 精品高清视频 | 国产又粗又猛又爽又黄的视频免费 | 午夜久久久精品 | 亚洲色五月 | 日韩在线观看视频免费 | 国产视频一区二区在线播放 | 日韩精品你懂的 | 极品中文字幕 | 久草.com| 久久精品国产精品 | 人人爱人人射 | 亚洲国产成人在线观看 | 国产69久久 | 一区二区三区四区久久 | 免费色视频网站 | 日韩最新在线视频 | 美女视频a美女大全免费下载蜜臀 | av中文在线观看 | 天天射天天舔天天干 | 精品国产乱码久久久久久1区二区 | 久久综合免费视频影院 | 久草视频在线播放 | 91在线视频在线 | 伊人影院得得 | 9草在线 | 天天综合成人网 | 天天天干夜夜夜操 | 婷婷久久综合九色综合 | 最新中文字幕在线播放 | 成人午夜av电影 | 欧美性爽爽 | 99久久日韩精品免费热麻豆美女 | 人人爽人人爽人人片av | 九九免费视频 | 日韩有码中文字幕在线 | 国产精品成人品 | 九九热视频在线播放 | 91国内在线视频 | 亚洲精品视频免费观看 | 狠狠干狠狠久久 | 免费视频a| 久久久久女教师免费一区 | 欧洲精品在线视频 | 亚洲一级电影在线观看 | 亚洲最大激情中文字幕 | 亚洲成人动漫在线观看 | 91香蕉视频在线 | 国产一区二区高清视频 | 免费福利片2019潦草影视午夜 | 久久久久伊人 | 亚州av免费 | 91在线看黄 | 久久五月精品 | 狠狠操影视| 久久久精品午夜 | 午夜精品久久久久久中宇69 | 成人午夜电影在线播放 | 国产一区电影在线观看 | 三级av在线免费观看 | 美女视频是黄的免费观看 | 一区二区三区中文字幕在线 | 久草在线网址 | 中文字幕a∨在线乱码免费看 | 欧美va天堂va视频va在线 | 国产精品麻豆三级一区视频 | 一本一本久久a久久 | 免费在线视频一区二区 | 欧美影院久久 | 亚洲三级性片 | 欧美a性| 国产精品福利久久久 | 天天干com | 久久蜜臀一区二区三区av | 狠狠干在线播放 | 欧美a级一区二区 | 国产精品成久久久久 | 999久久久欧美日韩黑人 | 干综合网 | av在线最新 | 国内精品亚洲 | 国产精品theporn | www.五月天激情 | 97精品视频在线 | 国产精品久久久久影视 | 人人爽人人乐 | 亚洲欧美日本一区二区三区 | 日韩av一区二区在线播放 | 激情婷婷综合 | 九月婷婷人人澡人人添人人爽 | 亚洲经典精品 | 狠狠色综合欧美激情 | 在线观看免费黄色 | 狠狠干成人综合网 | 国产亚洲一区二区三区 | 深夜成人av | 中文字幕第一页在线 | 久9在线| 丝袜精品视频 | 五月花激情| 十八岁以下禁止观看的1000个网站 | 视频一区在线免费观看 | 国产精品欧美一区二区三区不卡 | 欧美日韩免费在线视频 | 欧美大码xxxx | 黄色a一级片 | av在线最新 | 国产午夜精品福利视频 | 99色在线观看视频 | 美女国产免费 | 国产一级一片免费播放放a 一区二区三区国产欧美 | 色多多视频在线观看 | 亚洲精品久久久久久久不卡四虎 | 日韩欧美高清在线观看 | 免费电影一区二区三区 | 久久国产手机看片 | 精油按摩av| 国产裸体无遮挡 | 国产精品黄网站在线观看 | 日韩一区二区三区观看 | 亚洲天堂毛片 | www.在线看片.com | 99 色| 99久久日韩精品视频免费在线观看 | 成年人在线免费看视频 | 一级性生活片 | 日韩在线观看的 | 97综合在线 | 国产精品毛片一区视频播不卡 | 国产一级免费观看视频 | 久久精品爱爱视频 | 天天草天天操 | 久久 亚洲视频 | 久久精品一级片 | 久久精品综合视频 | 欧美综合色在线图区 | 免费国产在线精品 | 色多多污污| 亚洲区视频在线 | 中文字幕免费成人 | 欧美国产日韩一区二区三区 | www.久久免费| 91麻豆精品国产自产 | 久久人人精 | 国产综合香蕉五月婷在线 | 精品a在线 | 成人免费一级 | 超碰在线人人爱 | 国产精品热视频 | 久久精品国产亚洲a | 国产91综合一区在线观看 | 日韩精品最新在线观看 | 国产一性一爱一乱一交 | 色成人亚洲网 | av专区在线| 五月天色婷婷丁香 | 91传媒免费观看 | 在线观看精品黄av片免费 | 色成人亚洲网 | 日韩中文字幕免费 | 97视频一区 | 91完整版在线观看 | 国产亚洲无 | 在线天堂中文在线资源网 | av 一区 二区 久久 | 天天操综合网站 | 中文字幕乱在线伦视频中文字幕乱码在线 | 99视频在线精品国自产拍免费观看 | 久久久精品电影 | 午夜在线免费视频 | 婷婷新五月 | av综合 日韩| 亚洲视频h | a色视频 | av免费在线看网站 | 国产精品亚洲片在线播放 | 在线观看久久久久久 | 国产精品亚洲人在线观看 | 免费看片日韩 | 亚洲免费一级电影 | 91精品国产九九九久久久亚洲 | 伊人久久av | 亚洲人人网 | 日韩不卡高清 | 色狠狠综合天天综合综合 | 亚洲第一区精品 | 欧美激情另类 | 欧美精品中文 | 久久精品99国产精品 | 国产精品黄色 | 美女啪啪图片 | 激情欧美一区二区三区 | 一级黄色a视频 | 久久精品美女视频 | 久操操 | 日日夜夜噜噜噜 | 国产一级不卡视频 | 欧美人人爱| 四虎在线免费观看视频 | 成年人视频在线免费 | 人人插人人干 | 欧美日本在线观看视频 | 夜夜操天天操 | 久久一区二区三区国产精品 | 在线国产一区 | 日韩成人在线一区二区 | 久久久久久久久久亚洲精品 | 色丁香久久 | 日韩在线免费高清视频 | 午夜在线看片 | 国产成人一二片 | 国产午夜精品免费一区二区三区视频 | 玖玖视频精品 | 成人免费91| 天干啦夜天干天干在线线 | 91成人久久 | 天堂av在线免费 | 亚洲视频免费在线观看 | 人人视频网站 | 婷婷六月激情 | 91大神在线观看视频 | 中文字幕 婷婷 | 黄色毛片视频免费 | 中文字幕黄色av | 久久国产精品视频免费看 | 免费看的黄色 | 日韩性xxx| 久久久精品高清 | 午夜国产成人 | 成人av手机在线 | 91九色视频在线观看 | 亚洲欧美日本A∨在线观看 青青河边草观看完整版高清 | a黄色大片| 久久伊人国产精品 | 亚洲精品在线视频网站 | 最近中文字幕免费av | 国产一级在线视频 | 国产成人久久久77777 | 五月天综合激情 | 国产精品视频地址 | 国产原创在线观看 | 亚洲精品国产高清 | 探花视频在线观看免费版 | 亚洲成人av一区二区 | 在线精品播放 | 黄色在线看网站 | 久久欧美在线电影 | 高清有码中文字幕 | 久操视频在线播放 | 在线视频一二三 | av高清影院 | 91女人18片女毛片60分钟 | 五月婷婷丁香网 | 天天操天天摸天天射 | 在线观看国产中文字幕 | 五月婷婷丁香在线观看 | 久久精品久久国产 | www.色国产 | 精品免费久久久久 | 欧美精选一区二区三区 | 黄色1级大片| 国产尤物在线观看 | 久久国产精品99久久久久久丝袜 | 在线观看国产 | 国产精品久久99综合免费观看尤物 | 免费在线一区二区三区 | 婷婷成人亚洲综合国产xv88 | 一级片视频在线 | 中文字幕在线观看免费高清电影 | 久久无码精品一区二区三区 | 日本特黄特色aaa大片免费 | 日韩欧美xxxx | 天天综合网在线观看 | 麻豆免费观看视频 | 成人精品久久久 | 亚洲国产日韩一区 | 亚洲国产精品va在线看黑人 | 亚洲激精日韩激精欧美精品 | 一区二区理论片 | 亚洲综合导航 | 99精品国产福利在线观看免费 | 日本精品久久久久中文字幕 | 国产一卡在线 | 国产男女无遮挡猛进猛出在线观看 | 国产尤物视频在线 | 国产v在线观看 | 国产视频一区二区在线 | 97人人模人人爽人人少妇 | 欧美久久久影院 | 国产精品一区二区免费视频 | 欧美在线观看视频一区二区三区 | 久久精精品视频 | 91影视成人 | 99久精品视频| 狠狠色狠狠色综合日日小说 | 日韩欧美69 | 亚洲精品看片 | 欧美日韩不卡在线视频 | 丁香婷婷激情国产高清秒播 | 久久视屏网 | 国产精品免费久久久久影院仙踪林 | 日本成人中文字幕在线观看 | 人人射人人| 亚洲精品成人网 | 亚洲精品女人久久久 | 91亚洲精品久久久久图片蜜桃 | 国产精品第72页 | 97天堂网 | 超碰97av在线| 久久伊99综合婷婷久久伊 | 国产永久免费观看 | 国产视频在线观看一区 | 国产亚洲视频在线观看 | 热久久精品在线 | 久久久免费观看 | 九色在线视频 | 国产在线一线 | 国产精品久久久毛片 | 日韩精品中文字幕在线 | 成年人视频免费在线播放 | 人人精品久久 | 麻豆高清免费国产一区 | 一级黄色片网站 | 久久久久久蜜av免费网站 | av三级av | 日韩欧美在线国产 | 97夜夜澡人人爽人人免费 | 午夜av片| 成人性生交大片免费观看网站 | 欧美一区二区三区在线 | 麻豆传媒在线视频 | 久久精品视频国产 | 免费观看的av | 日韩电影在线一区 | 日韩免费在线 | 五月婷婷.com | 中文字幕资源网 国产 | 中文在线| 中文字幕在线一二 | 亚洲欧美日韩一级 | 最近日本中文字幕a | 中文资源在线观看 | 操久| 色综合久久久久久久 | 一级片免费观看视频 | 99热国内精品 | 精品国产aⅴ一区二区三区 在线直播av | 亚洲午夜激情网 | 国产精品免费一区二区三区 | 五月婷婷开心中文字幕 | 夜夜操网站 | 欧美伦理一区二区 | 精品视频久久 | 99精品免费久久久久久久久 | 亚州av成人| 在线国产视频一区 | 久草视频网| 91探花视频| 亚洲国产丝袜在线观看 | 精品国产一区二区三区免费 | 在线观看国产日韩欧美 | 中文字幕在线观看网 | 91热在线 | 超碰在线94 | 欧美在线观看小视频 | 天天摸日日操 | 干综合网| 在线免费三级 | 又湿又紧又大又爽a视频国产 | 精品国产乱码久久久久久久 | 亚洲日本一区二区在线 | 欧美激情视频久久 | 17婷婷久久www| 久久综合综合久久综合 | 日韩特黄av| 婷婷 中文字幕 | av成人在线播放 | 久久精品成人热国产成 | 亚洲精区二区三区四区麻豆 | 精品999在线观看 | 国产精品久久久久av免费 | 国产日韩精品一区二区在线观看播放 | 综合色伊人 | 天堂在线一区二区三区 | 国产福利资源 | 久要激情网 | 97香蕉视频| 国产一级片在线播放 | 精品女同一区二区三区在线观看 | 69视频国产| 国产亚洲综合性久久久影院 | 狠狠色狠狠色综合日日92 | 亚洲精品合集 | 中文字幕欧美日韩va免费视频 | 国产一区在线视频播放 | 日韩一区在线免费观看 | 四虎国产精 | 久久久久久久久久久免费av | 你操综合 | 国产精品成人在线 | 亚洲精品久久久蜜桃直播 | 在线免费日韩 | 国产成人免费精品 | 五月婷婷丁香六月 | 鲁一鲁影院 | 国产精品嫩草影院123 | 极品嫩模被强到高潮呻吟91 | 久久精品久久综合 | 国产美女精品视频免费观看 | 亚洲综合色婷婷 | 在线日韩精品视频 | 免费看国产精品 | 精品播放| 欧美精品一区二区免费 | 一区二区在线不卡 | 97国产精品亚洲精品 | 亚洲精品久 | 成人天堂网 | 久久精品一区二区国产 | 国产精品99久久久久久人免费 | 久久久久久久免费 | 国产精品一区二区免费看 | 中文字幕视频播放 | 99热国产精品 | av中文电影| 99精品乱码国产在线观看 | 黄色小说视频在线 | 久久久黄视频 | 亚洲精品综合久久 | 99热在线国产 | 婷婷精品在线视频 | 久久久国产视频 | 综合成人在线 | 国产精品精品国产色婷婷 | 久久久久综合精品福利啪啪 | 欧美日韩xx | 欧美日韩中文国产一区发布 | 成年人视频在线免费 | av黄色在线 | 91av国产视频 | 91综合色| wwxxx日本| 国产精品成人久久 | 在线中文字幕观看 | 性色av一区二区三区在线观看 | 日韩中文字幕免费视频 | 91看片在线免费观看 | 日韩大片在线免费观看 | 麻豆av一区二区三区在线观看 | 欧美巨乳网 | 免费一级特黄毛大片 | 色视频成人在线观看免 | 国产精品mm| 久久99热精品这里久久精品 | 日韩激情视频在线 | 91精品办公室少妇高潮对白 | 欧美男女爱爱视频 | 免费看国产一级片 | 久久精品网站视频 | 最新国产视频 | 精品国产乱码久久久久久三级人 | 97超碰在线播放 | 国产美女视频免费观看的网站 | 九九九九九国产 | 亚洲精品乱码白浆高清久久久久久 | 免费不卡中文字幕视频 | 国内视频 | 欧美analxxxx | 日韩精品一区二区三区第95 | 黄色电影小说 | 国产精品一区二区麻豆 | 欧美在线观看视频一区二区三区 | www.夜夜操.com | 在线涩涩 | 国产一区二区观看 | 日韩国产欧美在线视频 | 日韩av视屏在线观看 | 免费亚洲婷婷 | 国产精品九九久久99视频 | www.com黄色| 97人人澡人人添人人爽超碰 | 欧美久草视频 | 亚洲伊人色 | 国产传媒一区在线 | 成人a免费看 | 国产亚洲精品久久久久久久久久 | 亚洲 成人 一区 | 久久dvd| www.国产精品| 久久国产精品久久w女人spa | 久久香蕉一区 | 911国产精品| 2019精品手机国产品在线 | 一区二区三区视频在线 | 国产综合在线观看视频 | 日韩在线精品 | 婷婷丁香激情五月 | 一区二区三区国 | 99热精品视 | 日韩区欠美精品av视频 | 午夜久久电影网 | 一区二区免费不卡在线 | 久久综合9988久久爱 | 99热这里只有精品在线观看 | 亚洲精品影院在线观看 | 亚洲综合在线一区二区三区 | 久久深夜| 毛片视频网址 | av电影免费观看 | 国产精品久久久久免费a∨ 欧美一级性生活片 | 又粗又长又大又爽又黄少妇毛片 | 中文字幕在线高清 | 天天天综合网 | 欧美日韩不卡一区二区三区 | 蜜臀av性久久久久蜜臀aⅴ四虎 | 国产va精品免费观看 | 韩日电影在线免费看 | 特级大胆西西4444www | 久久精品一区二区三区中文字幕 | 看片在线亚洲 | 欧美精品免费一区二区 | 国产视频在线观看免费 | 国内少妇自拍视频一区 | 婷婷六月色| 中文字幕黄色 | 91免费日韩| 91精品一区在线观看 | 日韩欧美高清一区二区三区 | 欧美一级网站 | 丰满少妇一级片 | 中文字幕在线观看不卡 | 久久一区二区免费视频 | 麻豆传媒视频在线播放 | 国产手机av在线 | 伊人一级 | 欧美另类性 | 国产精品久久久久婷婷 | 欧美一级视频在线观看 | 国产精品久久久久久久久久新婚 | 在线中文字幕av观看 | 日韩精品综合在线 | 色九九在线 | 在线免费观看麻豆 | 精品美女视频 | 国产美女黄网站免费 | 久草剧场 | 99久久99久久免费精品蜜臀 | 久久伊人操 | 最近中文字幕完整高清 | 中文字幕在线观看av | 久久久久国产精品厨房 | 美女精品在线观看 | 最新av在线播放 | 国产免费高清视频 | 三级黄色三级 | 日韩三级免费观看 | 欧美精品xxx| 久久福利国产 | 激情综合婷婷 | 黄色大全免费观看 | 五月丁婷婷| 国产色视频一区二区三区qq号 | 成人黄色电影免费观看 | 久久99这里只有精品 | 久草在线免费在线观看 | 亚洲精品美女久久久久网站 | 91中文在线观看 | 天天操天天射天天插 | 四虎天堂 | 精品国产乱码久久久久久久 | 中文字幕中文字幕在线一区 | 日韩aⅴ视频 | 国产99久久久精品 | 中文字幕在线电影 | 在线一级片 | 日韩免费高清在线观看 | 亚洲国产成人久久 | 亚洲精品久久久久58 | 欧美日韩亚洲在线观看 | 久久99国产精品久久 | 欧美在线视频一区二区三区 | 久久久久在线观看 | 91精品视频一区 | 激情欧美日韩一区二区 | 成人免费网站视频 | 中国精品一区二区 | 亚洲国产精品免费 |