Program Listing for File SE3Tracker.cpp¶
↰ Return to documentation for file (lib/Tracking/SE3Tracker.cpp)
#include <sstream>
using std::stringstream;
#include "SE3Tracker.h"
#include <opencv2/highgui/highgui.hpp>
#include "DataStructures/Frame.h"
#include "DataStructures/KeyFrame.h"
#include "Tracking/TrackingReference.h"
#include "util/globalFuncs.h"
#include "IOWrapper/ImageDisplay.h"
#include "Tracking/LGSX.h"
namespace lsd_slam {
#if defined(ENABLE_NEON)
#define callOptimized(function, arguments) function##NEON arguments
#else
#if defined(ENABLE_SSE)
#error "SSE Enabled!"
#define callOptimized(function, arguments) (USESSE ? function##SSE arguments : function arguments)
#else
#define callOptimized(function, arguments) function arguments
#endif
#endif
SE3Tracker::SE3Tracker(const ImageSize &sz )
: _pctGoodPerGoodBad(-1.0),
_pctGoodPerTotal(-1.0),
_lastGoodCount(0),
_lastBadCount(0),
_imgSize( sz ),
_debugImages( sz ),
settings()
{
const int area = _imgSize.area();
buf_warped_residual = new float[area];
buf_warped_dx = new float[area];
buf_warped_dy = new float[area];
buf_warped_x = new float[area];
buf_warped_y = new float[area];
buf_warped_z = new float[area];
buf_d = new float[area];
buf_idepthVar = new float[area];
buf_weight_p = new float[area];
buf_warped_size = 0;
lastResidual = 0;
iterationNumber = 0;
pointUsage = 0;
diverged = false;
}
SE3Tracker::~SE3Tracker()
{
delete[] buf_warped_residual;
delete[] buf_warped_dx;
delete[] buf_warped_dy;
delete[] buf_warped_x;
delete[] buf_warped_y;
delete[] buf_warped_z;
delete[] buf_d;
delete[] buf_idepthVar;
delete[] buf_weight_p;
}
// Calculates the percentage overlap between the two keyframes
float SE3Tracker::checkPermaRefOverlap(
const std::shared_ptr<KeyFrame> &reference,
SE3 referenceToFrameOrg)
{
Sophus::SE3f referenceToFrame = referenceToFrameOrg.cast<float>();
//boost::unique_lock<boost::mutex> lock2 = boost::unique_lock<boost::mutex>(reference->permaRef_mutex);
const std::shared_ptr<Frame> &frame( reference->frame() );
const std::shared_ptr<TrackingReference> &ref( reference->trackingReference() );
const int w2 = frame->width(QUICK_KF_CHECK_LVL)-1;
const int h2 = frame->height(QUICK_KF_CHECK_LVL)-1;
const Eigen::Matrix3f KLvl = frame->K(QUICK_KF_CHECK_LVL);
const float fx_l = KLvl(0,0);
const float fy_l = KLvl(1,1);
const float cx_l = KLvl(0,2);
const float cy_l = KLvl(1,2);
Eigen::Matrix3f rotMat = referenceToFrame.rotationMatrix();
Eigen::Vector3f transVec = referenceToFrame.translation();
const Eigen::Vector3f* refPoint_max = ref->posData[QUICK_KF_CHECK_LVL] + ref->numData[QUICK_KF_CHECK_LVL];
const Eigen::Vector3f* refPoint = ref->posData[QUICK_KF_CHECK_LVL];
float usageCount = 0;
for(;refPoint<refPoint_max; refPoint++)
{
Eigen::Vector3f Wxp = rotMat * (*refPoint) + transVec;
float u_new = (Wxp[0]/Wxp[2])*fx_l + cx_l;
float v_new = (Wxp[1]/Wxp[2])*fy_l + cy_l;
if((u_new > 0 && v_new > 0 && u_new < w2 && v_new < h2))
{
float depthChange = (*refPoint)[2] / Wxp[2];
usageCount += depthChange < 1 ? depthChange : 1;
}
}
pointUsage = usageCount / (float)ref->numData[QUICK_KF_CHECK_LVL];
return pointUsage;
}
// tracks a frame.
// first_frame has depth, second_frame DOES NOT have depth.
SE3 SE3Tracker::trackFrameOnPermaref(
const std::shared_ptr<KeyFrame> &reference,
const std::shared_ptr<Frame> &frame,
SE3 referenceToFrameOrg)
{
const std::shared_ptr<TrackingReference> &ref( reference->trackingReference() );
Sophus::SE3f referenceToFrame = referenceToFrameOrg.cast<float>();
affineEstimation_a = 1; affineEstimation_b = 0;
LGS6 ls;
diverged = false;
trackingWasGood = true;
callOptimized(calcResidualAndBuffers, (ref->posData[QUICK_KF_CHECK_LVL], ref->colorAndVarData[QUICK_KF_CHECK_LVL], 0, ref->numData[QUICK_KF_CHECK_LVL], frame, referenceToFrame, QUICK_KF_CHECK_LVL, false));
if(buf_warped_size < MIN_GOODPERALL_PIXEL_ABSMIN * (_imgSize.width>>QUICK_KF_CHECK_LVL)*(_imgSize.height>>QUICK_KF_CHECK_LVL))
{
diverged = true;
trackingWasGood = false;
return SE3();
}
if(useAffineLightningEstimation)
{
affineEstimation_a = affineEstimation_a_lastIt;
affineEstimation_b = affineEstimation_b_lastIt;
}
float lastErr = callOptimized(calcWeightsAndResidual,(referenceToFrame));
float LM_lambda = settings.lambdaInitialTestTrack;
for(int iteration=0; iteration < settings.maxItsTestTrack; iteration++)
{
callOptimized(calculateWarpUpdate,(ls));
int incTry=0;
while(true)
{
// solve LS system with current lambda
Vector6 b = -ls.b;
Matrix6x6 A = ls.A;
for(int i=0;i<6;i++) A(i,i) *= 1+LM_lambda;
Vector6 inc = A.ldlt().solve(b);
incTry++;
// apply increment. pretty sure this way round is correct, but hard to test.
Sophus::SE3f new_referenceToFrame = Sophus::SE3f::exp((inc)) * referenceToFrame;
// re-evaluate residual
callOptimized(calcResidualAndBuffers, (ref->posData[QUICK_KF_CHECK_LVL], ref->colorAndVarData[QUICK_KF_CHECK_LVL], 0, ref->numData[QUICK_KF_CHECK_LVL], frame, new_referenceToFrame, QUICK_KF_CHECK_LVL, false));
if(buf_warped_size < MIN_GOODPERALL_PIXEL_ABSMIN * (_imgSize.width>>QUICK_KF_CHECK_LVL)*(_imgSize.height>>QUICK_KF_CHECK_LVL))
{
diverged = true;
trackingWasGood = false;
return SE3();
}
float error = callOptimized(calcWeightsAndResidual,(new_referenceToFrame));
// accept inc?
if(error < lastErr)
{
// accept inc
referenceToFrame = new_referenceToFrame;
if(useAffineLightningEstimation)
{
affineEstimation_a = affineEstimation_a_lastIt;
affineEstimation_b = affineEstimation_b_lastIt;
}
// converged?
if(error / lastErr > settings.convergenceEpsTestTrack)
iteration = settings.maxItsTestTrack;
lastErr = error;
if(LM_lambda <= 0.2)
LM_lambda = 0;
else
LM_lambda *= settings.lambdaSuccessFac;
break;
}
else
{
if(!(inc.dot(inc) > settings.stepSizeMinTestTrack))
{
iteration = settings.maxItsTestTrack;
break;
}
if(LM_lambda == 0)
LM_lambda = 0.2;
else
LM_lambda *= std::pow(settings.lambdaFailFac, incTry);
}
}
}
lastResidual = lastErr;
_pctGoodPerTotal = _lastGoodCount / (frame->width(QUICK_KF_CHECK_LVL)*frame->height(QUICK_KF_CHECK_LVL));
_pctGoodPerGoodBad = _lastGoodCount / (_lastGoodCount + _lastBadCount);
trackingWasGood = !diverged
&& _pctGoodPerTotal > MIN_GOODPERALL_PIXEL
&& _pctGoodPerGoodBad > MIN_GOODPERGOODBAD_PIXEL;
return toSophus(referenceToFrame);
}
// tracks a frame.
SE3 SE3Tracker::trackFrame(
const std::shared_ptr<KeyFrame> &keyframe,
const std::shared_ptr<Frame> &frame,
const SE3& frameToReference_initialEstimate)
{
std::shared_ptr<TrackingReference> &reference( keyframe->trackingReference() );
boost::shared_lock<boost::shared_mutex> lock = frame->getActiveLock();
diverged = false;
trackingWasGood = true;
affineEstimation_a = 1; affineEstimation_b = 0;
if(saveAllTrackingStages)
{
saveAllTrackingStages = false;
saveAllTrackingStagesInternal = true;
}
if (plotTrackingIterationInfo)
{
const float* frameImage = frame->image();
for (int row = 0; row < _imgSize.height; ++ row)
for (int col = 0; col < _imgSize.height; ++ col)
setPixelInCvMat(&_debugImages.debugImageSecondFrame,getGrayCvPixel(frameImage[col+row*_imgSize.width]), col, row, 1);
}
// ============ track frame ============
Sophus::SE3f referenceToFrame = frameToReference_initialEstimate.inverse().cast<float>();
LGS6 ls;
int numCalcResidualCalls[PYRAMID_LEVELS];
int numCalcWarpUpdateCalls[PYRAMID_LEVELS];
float last_residual = 0;
int lowestLvl;
for(int lvl=SE3TRACKING_MAX_LEVEL-1; lvl >= SE3TRACKING_MIN_LEVEL; lvl-- )
{
numCalcResidualCalls[lvl] = 0;
numCalcWarpUpdateCalls[lvl] = 0;
lowestLvl = lvl;
reference->makePointCloud(lvl);
LOG(INFO) << "Calculating initial residual on frame " << frame->id() << ", level " << lvl << " against reference frame " << reference->frameID() << " with " << reference->numData[lvl] << " points";
callOptimized(calcResidualAndBuffers, (reference->posData[lvl],
reference->colorAndVarData[lvl],
SE3TRACKING_MIN_LEVEL == lvl ? reference->pointPosInXYGrid[lvl] : 0,
reference->numData[lvl],
frame, referenceToFrame, lvl,
(plotTracking && lvl == SE3TRACKING_MIN_LEVEL)));
if(buf_warped_size < MIN_GOODPERALL_PIXEL_ABSMIN * (_imgSize.width>>lvl)*(_imgSize.height>>lvl))
{
diverged = true;
trackingWasGood = false;
LOG(INFO) << "Diverged at level " << lvl << "! Only " << buf_warped_size << " pixel to track.";
return SE3();
}
if(useAffineLightningEstimation)
{
affineEstimation_a = affineEstimation_a_lastIt;
affineEstimation_b = affineEstimation_b_lastIt;
}
float lastErr = callOptimized(calcWeightsAndResidual,(referenceToFrame));
numCalcResidualCalls[lvl]++;
float LM_lambda = settings.lambdaInitial[lvl];
for(int iteration=0; iteration < settings.maxItsPerLvl[lvl]; iteration++)
{
callOptimized(calculateWarpUpdate,(ls));
numCalcWarpUpdateCalls[lvl]++;
iterationNumber = iteration;
int incTry=0;
while(true)
{
// solve LS system with current lambda
Vector6 b = -ls.b;
Matrix6x6 A = ls.A;
for(int i=0;i<6;i++) A(i,i) *= 1+LM_lambda;
Vector6 inc = A.ldlt().solve(b);
incTry++;
// apply increment. pretty sure this way round is correct, but hard to test.
//Sophus::SE3f exp_increment = Sophus::SE3f::exp((inc));
Sophus::SE3f new_referenceToFrame = Sophus::SE3f::exp((inc)) * referenceToFrame;
//Sophus::SE3f new_referenceToFrame = referenceToFrame * Sophus::SE3f::exp((inc));
// re-evaluate residual
callOptimized(calcResidualAndBuffers, (reference->posData[lvl], reference->colorAndVarData[lvl],
SE3TRACKING_MIN_LEVEL == lvl ? reference->pointPosInXYGrid[lvl] : 0, reference->numData[lvl],
frame, new_referenceToFrame, lvl, (plotTracking && lvl == SE3TRACKING_MIN_LEVEL)));
if(buf_warped_size < MIN_GOODPERALL_PIXEL_ABSMIN* (_imgSize.width>>lvl)*(_imgSize.height>>lvl))
{
diverged = true;
trackingWasGood = false;
LOG(INFO) << "Diverged at level " << lvl << " on iteration " << iteration << "! Only " << buf_warped_size << " pixels to track.";
return SE3();
}
float error = callOptimized(calcWeightsAndResidual,(new_referenceToFrame));
numCalcResidualCalls[lvl]++;
// accept inc?
if(error < lastErr)
{
// accept inc
referenceToFrame = new_referenceToFrame;
if(useAffineLightningEstimation)
{
affineEstimation_a = affineEstimation_a_lastIt;
affineEstimation_b = affineEstimation_b_lastIt;
}
LOGF_IF(DEBUG, Conf().print.trackingIterationInfo,"(%d-%d): ACCEPTED increment of %f with lambda %.1f, residual: %f > %f",
lvl,iteration, sqrt(inc.dot(inc)), LM_lambda, lastErr, error);
// converged?
if(error / lastErr > settings.convergenceEps[lvl])
{
LOGF_IF(DEBUG, Conf().print.trackingIterationInfo,"(%d-%d): FINISHED pyramid level (last residual reduction too small).",
lvl,iteration);
iteration = settings.maxItsPerLvl[lvl];
}
last_residual = lastErr = error;
if(LM_lambda <= 0.2)
LM_lambda = 0;
else
LM_lambda *= settings.lambdaSuccessFac;
break;
}
else
{
LOGF_IF(DEBUG,Conf().print.trackingIterationInfo,"(%d-%d): REJECTED increment of %f with lambda %.1f, (residual: %f < %f).",
lvl,iteration, sqrt(inc.dot(inc)), LM_lambda, lastErr, error);
if(!(inc.dot(inc) > settings.stepSizeMin[lvl]))
{
LOGF_IF(DEBUG,Conf().print.trackingIterationInfo,"(%d-%d): FINISHED pyramid level (stepsize too small).",
lvl,iteration);
iteration = settings.maxItsPerLvl[lvl];
break;
}
if(LM_lambda == 0)
LM_lambda = 0.2;
else
LM_lambda *= std::pow(settings.lambdaFailFac, incTry);
}
}
}
}
if(plotTracking)
Util::displayImage("TrackingResidual", _debugImages.debugImageResiduals, false);
if(Conf().print.trackingIterationInfo)
{
stringstream outstr;
outstr << "SE3 Tracking: ";
for(int lvl=PYRAMID_LEVELS-1;lvl >= lowestLvl;lvl--)
{
outstr << "lvl " << lvl << ": " << numCalcResidualCalls[lvl] << " (" << numCalcWarpUpdateCalls[lvl] << "); ";
}
LOG(DEBUG) << outstr.str();
}
saveAllTrackingStagesInternal = false;
lastResidual = last_residual;
_pctGoodPerTotal = _lastGoodCount / (frame->width(SE3TRACKING_MIN_LEVEL)*frame->height(SE3TRACKING_MIN_LEVEL));
_pctGoodPerGoodBad = _lastGoodCount / (_lastGoodCount + _lastBadCount);
LOG_IF(DEBUG, Conf().print.trackingIterationInfo ) << "lastGoodCount " << _lastGoodCount << " lastBadCount " << _lastBadCount;
//LOG_IF(DEBUG, Conf().print.trackingIterationInfo ) << frame->width(SE3TRACKING_MIN_LEVEL) << " " << frame->height(SE3TRACKING_MIN_LEVEL);
//LOG_IF(DEBUG, Conf().print.trackingIterationInfo ) << _pctGoodPerTotal << " " << _pctGoodPerGoodBad;
trackingWasGood = !diverged
&& _pctGoodPerTotal > MIN_GOODPERALL_PIXEL
&& _pctGoodPerGoodBad > MIN_GOODPERGOODBAD_PIXEL;
if(trackingWasGood) keyframe->numFramesTrackedOnThis++;
frame->initialTrackedResidual = lastResidual / pointUsage;
frame->pose->thisToParent_raw = sim3FromSE3(toSophus(referenceToFrame.inverse()),1);
frame->setTrackingParent( keyframe );
return toSophus(referenceToFrame.inverse());
}
float SE3Tracker::calcWeightsAndResidual(
const Sophus::SE3f& referenceToFrame)
{
float tx = referenceToFrame.translation()[0];
float ty = referenceToFrame.translation()[1];
float tz = referenceToFrame.translation()[2];
float sumRes = 0;
for(int i=0;i<buf_warped_size;i++)
{
float px = *(buf_warped_x+i); // x'
float py = *(buf_warped_y+i); // y'
float pz = *(buf_warped_z+i); // z'
float d = *(buf_d+i); // d
float rp = *(buf_warped_residual+i); // r_p
float gx = *(buf_warped_dx+i); // \delta_x I
float gy = *(buf_warped_dy+i); // \delta_y I
float s = settings.var_weight * *(buf_idepthVar+i); // \sigma_d^2
// calc dw/dd (first 2 components):
float g0 = (tx * pz - tz * px) / (pz*pz*d);
float g1 = (ty * pz - tz * py) / (pz*pz*d);
// calc w_p
float drpdd = gx * g0 + gy * g1; // ommitting the minus
float w_p = 1.0f / ((cameraPixelNoise2) + s * drpdd * drpdd);
float weighted_rp = fabs(rp*sqrtf(w_p));
float wh = fabs(weighted_rp < (settings.huber_d/2) ? 1 : (settings.huber_d/2) / weighted_rp);
sumRes += wh * w_p * rp*rp;
*(buf_weight_p+i) = wh * w_p;
}
return sumRes / buf_warped_size;
}
void SE3Tracker::calcResidualAndBuffers_debugStart()
{
if(plotTrackingIterationInfo || saveAllTrackingStagesInternal)
{
int other = saveAllTrackingStagesInternal ? 255 : 0;
fillCvMat(&_debugImages.debugImageResiduals,cv::Vec3b(other,other,255));
fillCvMat(&_debugImages.debugImageWeights,cv::Vec3b(other,other,255));
fillCvMat(&_debugImages.debugImageOldImageSource,cv::Vec3b(other,other,255));
fillCvMat(&_debugImages.debugImageOldImageWarped,cv::Vec3b(other,other,255));
}
}
void SE3Tracker::calcResidualAndBuffers_debugFinish(int w)
{
if(plotTrackingIterationInfo)
{
Util::displayImage( "Weights", _debugImages.debugImageWeights );
Util::displayImage( "second_frame", _debugImages.debugImageSecondFrame );
Util::displayImage( "Intensities of second_frame at transformed positions", _debugImages.debugImageOldImageSource );
Util::displayImage( "Intensities of second_frame at pointcloud in first_frame", _debugImages.debugImageOldImageWarped );
Util::displayImage( "Residuals", _debugImages.debugImageResiduals );
}
if(saveAllTrackingStagesInternal)
{
char charbuf[500];
snprintf(charbuf,500,"save/%sresidual-%d-%d.png",packagePath.c_str(),w,iterationNumber);
cv::imwrite(charbuf,_debugImages.debugImageResiduals);
snprintf(charbuf,500,"save/%swarped-%d-%d.png",packagePath.c_str(),w,iterationNumber);
cv::imwrite(charbuf,_debugImages.debugImageOldImageWarped);
snprintf(charbuf,500,"save/%sweights-%d-%d.png",packagePath.c_str(),w,iterationNumber);
cv::imwrite(charbuf,_debugImages.debugImageWeights);
printf("saved three images for lvl %d, iteration %d\n",w,iterationNumber);
}
}
float SE3Tracker::calcResidualAndBuffers(
const Eigen::Vector3f* refPoint,
const Eigen::Vector2f* refColVar,
int* idxBuf,
int refNum,
const std::shared_ptr<Frame> &frame,
const Sophus::SE3f& referenceToFrame,
int level,
bool plotResidual)
{
calcResidualAndBuffers_debugStart();
if(plotResidual) _debugImages.debugImageResiduals.setTo(0);
int w = frame->width(level);
int h = frame->height(level);
Eigen::Matrix3f KLvl = frame->K(level);
float fx_l = KLvl(0,0);
float fy_l = KLvl(1,1);
float cx_l = KLvl(0,2);
float cy_l = KLvl(1,2);
Eigen::Matrix3f rotMat = referenceToFrame.rotationMatrix();
Eigen::Vector3f transVec = referenceToFrame.translation();
const Eigen::Vector3f* refPoint_max = refPoint + refNum;
const Eigen::Vector4f* frame_gradients = frame->gradients(level);
int idx=0;
float sumResUnweighted = 0;
bool* isGoodOutBuffer = idxBuf != 0 ? frame->refPixelWasGood() : 0;
int goodCount = 0;
int badCount = 0;
float sumSignedRes = 0;
float sxx=0,syy=0,sx=0,sy=0,sw=0;
float usageCount = 0;
//LOG(DEBUG) << refNum << ": " << *refPoint << " < " << *refPoint_max;
// LOG(DEBUG) << "Rotmat: " << rotMat;
// LOG(DEBUG) << "transVec: " << transVec;
int loop = 0;
for(;refPoint<refPoint_max; refPoint++, refColVar++, idxBuf++, loop++)
{
Eigen::Vector3f Wxp = rotMat * (*refPoint) + transVec;
float u_new = (Wxp[0]/Wxp[2])*fx_l + cx_l;
float v_new = (Wxp[1]/Wxp[2])*fy_l + cy_l;
// step 1a: coordinates have to be in image:
// (inverse test to exclude NANs)
if(!(u_new > 1 && v_new > 1 && u_new < w-2 && v_new < h-2))
{
if(isGoodOutBuffer != 0) isGoodOutBuffer[*idxBuf] = false;
// LOG_IF(DEBUG, loop < 50) << "Ref point: " << (*refPoint)[0] << " " << (*refPoint)[1] << " " << (*refPoint)[2];
// LOG_IF(DEBUG, loop < 50) << "Wxp :" << Wxp[0] << " " << Wxp[1] << " " << Wxp[2] << " maps to " << u_new << " " << v_new;
continue;
}
Eigen::Vector3f resInterp = getInterpolatedElement43(frame_gradients, u_new, v_new, w);
float c1 = affineEstimation_a * (*refColVar)[0] + affineEstimation_b;
float c2 = resInterp[2];
float residual = c1 - c2;
float weight = fabsf(residual) < 5.0f ? 1 : 5.0f / fabsf(residual);
sxx += c1*c1*weight;
syy += c2*c2*weight;
sx += c1*weight;
sy += c2*weight;
sw += weight;
bool isGood = residual*residual / (MAX_DIFF_CONSTANT + MAX_DIFF_GRAD_MULT*(resInterp[0]*resInterp[0] + resInterp[1]*resInterp[1])) < 1;
if(isGoodOutBuffer != 0)
isGoodOutBuffer[*idxBuf] = isGood;
*(buf_warped_x+idx) = Wxp(0);
*(buf_warped_y+idx) = Wxp(1);
*(buf_warped_z+idx) = Wxp(2);
*(buf_warped_dx+idx) = fx_l * resInterp[0];
*(buf_warped_dy+idx) = fy_l * resInterp[1];
*(buf_warped_residual+idx) = residual;
*(buf_d+idx) = 1.0f / (*refPoint)[2];
*(buf_idepthVar+idx) = (*refColVar)[1];
idx++;
if(isGood)
{
sumResUnweighted += residual*residual;
sumSignedRes += residual;
goodCount++;
}
else
badCount++;
float depthChange = (*refPoint)[2] / Wxp[2]; // if depth becomes larger: pixel becomes "smaller", hence count it less.
usageCount += depthChange < 1 ? depthChange : 1;
// DEBUG STUFF
if(plotTrackingIterationInfo || plotResidual)
{
// for debug plot only: find x,y again.
// horribly inefficient, but who cares at this point...
int width = _imgSize.width;
Eigen::Vector3f point = KLvl * (*refPoint);
int x = point[0] / point[2] + 0.5f;
int y = point[1] / point[2] + 0.5f;
if(plotTrackingIterationInfo)
{
setPixelInCvMat(&_debugImages.debugImageOldImageSource,getGrayCvPixel((float)resInterp[2]),u_new+0.5,v_new+0.5,(width/w));
setPixelInCvMat(&_debugImages.debugImageOldImageWarped,getGrayCvPixel((float)resInterp[2]),x,y,(width/w));
}
if(isGood)
setPixelInCvMat(&_debugImages.debugImageResiduals,getGrayCvPixel(residual+128),x,y,(width/w));
else
setPixelInCvMat(&_debugImages.debugImageResiduals,cv::Vec3b(0,0,255),x,y,(width/w));
}
}
buf_warped_size = idx;
pointUsage = usageCount / (float)refNum;
_lastGoodCount = goodCount;
_lastBadCount = badCount;
lastMeanRes = sumSignedRes / goodCount;
LOG_IF(DEBUG, Conf().print.trackingIterationInfo ) << "loop: " << loop << " buf_warped_size = " << buf_warped_size << "; goodCount = " << goodCount << "; badCount = " << badCount;
// if( buf_warped_size == 0 ) {
// LOG(DEBUG) << "Trap!";
// }
affineEstimation_a_lastIt = sqrtf((syy - sy*sy/sw) / (sxx - sx*sx/sw));
affineEstimation_b_lastIt = (sy - affineEstimation_a_lastIt*sx)/sw;
calcResidualAndBuffers_debugFinish(w);
return sumResUnweighted / goodCount;
}
void SE3Tracker::calculateWarpUpdate(
LGS6 &ls)
{
// weightEstimator.reset();
// weightEstimator.estimateDistribution(buf_warped_residual, buf_warped_size);
// weightEstimator.calcWeights(buf_warped_residual, buf_warped_weights, buf_warped_size);
//
ls.initialize(_imgSize.area());
for(int i=0;i<buf_warped_size;i++)
{
float px = *(buf_warped_x+i);
float py = *(buf_warped_y+i);
float pz = *(buf_warped_z+i);
float r = *(buf_warped_residual+i);
float gx = *(buf_warped_dx+i);
float gy = *(buf_warped_dy+i);
// step 3 + step 5 comp 6d error vector
float z = 1.0f / pz;
float z_sqr = 1.0f / (pz*pz);
Vector6 v;
v[0] = z*gx + 0;
v[1] = 0 + z*gy;
v[2] = (-px * z_sqr) * gx +
(-py * z_sqr) * gy;
v[3] = (-px * py * z_sqr) * gx +
(-(1.0 + py * py * z_sqr)) * gy;
v[4] = (1.0 + px * px * z_sqr) * gx +
(px * py * z_sqr) * gy;
v[5] = (-py * z) * gx +
(px * z) * gy;
// step 6: integrate into A and b:
ls.update(v, r, *(buf_weight_p+i));
}
// solve ls
ls.finish();
//result = ls.A.ldlt().solve(ls.b);
}
//=== SE3TrackerDebugImages ==
SE3TrackerDebugImages::SE3TrackerDebugImages( const ImageSize &imgSize )
: debugImageWeights( cv::Mat(imgSize.cvSize(),CV_8UC3) ),
debugImageResiduals( cv::Mat(imgSize.cvSize(),CV_8UC3) ),
debugImageSecondFrame( cv::Mat(imgSize.cvSize(),CV_8UC3) ),
debugImageOldImageWarped( cv::Mat(imgSize.cvSize(),CV_8UC3) ),
debugImageOldImageSource( cv::Mat(imgSize.cvSize(),CV_8UC3) )
{;}
}