Commit 02124f19 authored by Olexa Bilaniuk's avatar Olexa Bilaniuk

Further LevMarq improvements.

Implemented a damping-parameter choice strategy similar to that
described in http://www2.imm.dtu.dk/documents/ftp/tr99/tr05_99.pdf.
Removed a few debug statements.
Chosen a new starting lambda value, 0.01.
We now actually output the mask of inliers.
parent ff91af82
...@@ -287,7 +287,9 @@ static bool createAndRunRHORegistrator(double confidence, int maxIters, double r ...@@ -287,7 +287,9 @@ static bool createAndRunRHORegistrator(double confidence, int maxIters, double r
/* Run RHO. Needs cleanup or separate function to invoke. */ /* Run RHO. Needs cleanup or separate function to invoke. */
Mat tmpH = Mat(3, 3, CV_32FC1); Mat tmpH = Mat(3, 3, CV_32FC1);
tempMask = Mat(npoints, 1, CV_8U); if(!tempMask.data){
tempMask = Mat(npoints, 1, CV_8U);
}
double beta = 0.35;/* 0.35 is a value that often works. */ double beta = 0.35;/* 0.35 is a value that often works. */
#if CV_SSE2 && 0 #if CV_SSE2 && 0
...@@ -339,6 +341,7 @@ static bool createAndRunRHORegistrator(double confidence, int maxIters, double r ...@@ -339,6 +341,7 @@ static bool createAndRunRHORegistrator(double confidence, int maxIters, double r
for(int k=0;k<npoints;k++){ for(int k=0;k<npoints;k++){
tempMask.data[k] = !!tempMask.data[k]; tempMask.data[k] = !!tempMask.data[k];
} }
tempMask.copyTo(_tempMask);
return result; return result;
} }
......
...@@ -72,6 +72,8 @@ ...@@ -72,6 +72,8 @@
#define SPRT_M_S 1 /* 1 model per sample */ #define SPRT_M_S 1 /* 1 model per sample */
#define SPRT_EPSILON 0.1 /* No explanation */ #define SPRT_EPSILON 0.1 /* No explanation */
#define SPRT_DELTA 0.01 /* No explanation */ #define SPRT_DELTA 0.01 /* No explanation */
#define LM_GAIN_LO 0.25 /* See sacLMGain(). */
#define LM_GAIN_HI 0.75 /* See sacLMGain(). */
...@@ -140,9 +142,11 @@ static inline void sacCalcJacobianErrors(const float* restrict H, ...@@ -140,9 +142,11 @@ static inline void sacCalcJacobianErrors(const float* restrict H,
float (* restrict JtJ)[8], float (* restrict JtJ)[8],
float* restrict Jte, float* restrict Jte,
float* restrict Sp); float* restrict Sp);
static inline float sacDs(const float (*JtJ)[8], static inline float sacLMGain(const float* dH,
const float* dH, const float* Jte,
const float* Jte); const float S,
const float newS,
const float lambda);
static inline int sacChol8x8Damped (const float (*A)[8], static inline int sacChol8x8Damped (const float (*A)[8],
float lambda, float lambda,
float (*L)[8]); float (*L)[8]);
...@@ -1571,27 +1575,15 @@ static inline int sacCanRefine(RHO_HEST_REFC* p){ ...@@ -1571,27 +1575,15 @@ static inline int sacCanRefine(RHO_HEST_REFC* p){
return p->best.numInl > m; return p->best.numInl > m;
} }
static inline void dumpMat8x8(float (*M)[8]){
for(int i=0;i<8;i++){
printf("\t");
for(int j=0;j<=i;j++){
printf("%14.6e%s", M[i][j], j==i?"\n":", ");
}
}
printf("\n");
}
/** /**
* Refines the best-so-far homography (p->best.H). * Refines the best-so-far homography (p->best.H).
*/ */
static inline void sacRefine(RHO_HEST_REFC* p){ static inline void sacRefine(RHO_HEST_REFC* p){
int i = 0; int i;
float S = 0, newS = 0, dS = 0;/* Sum of squared errors */ float S, newS; /* Sum of squared errors */
float R = 0; /* R - Parameter */ float gain; /* Gain-parameter. */
float L = 1.0f; /* Lambda of LevMarq */ float L = 0.01f;/* Lambda of LevMarq */
float dH[8], newH[8]; float dH[8], newH[8];
/** /**
...@@ -1601,7 +1593,6 @@ static inline void sacRefine(RHO_HEST_REFC* p){ ...@@ -1601,7 +1593,6 @@ static inline void sacRefine(RHO_HEST_REFC* p){
/* Find initial conditions */ /* Find initial conditions */
sacCalcJacobianErrors(p->best.H, p->arg.src, p->arg.dst, p->arg.inl, p->arg.N, sacCalcJacobianErrors(p->best.H, p->arg.src, p->arg.dst, p->arg.inl, p->arg.N,
p->lm.JtJ, p->lm.Jte, &S); p->lm.JtJ, p->lm.Jte, &S);
/*printf("Initial Error: %12.6f\n", S);*/
/*Levenberg-Marquardt Loop.*/ /*Levenberg-Marquardt Loop.*/
for(i=0;i<MAXLEVMARQITERS;i++){ for(i=0;i<MAXLEVMARQITERS;i++){
...@@ -1626,37 +1617,42 @@ static inline void sacRefine(RHO_HEST_REFC* p){ ...@@ -1626,37 +1617,42 @@ static inline void sacRefine(RHO_HEST_REFC* p){
* transpose) then multiply JtJ in order to find dH. * transpose) then multiply JtJ in order to find dH.
*/ */
/*printf("Lambda: %f\n", L);*/
while(!sacChol8x8Damped(p->lm.JtJ, L, p->lm.tmp1)){ while(!sacChol8x8Damped(p->lm.JtJ, L, p->lm.tmp1)){
L *= 2.0f;/*printf("CholFail! Lambda: %f\n", L);*/ L *= 2.0f;
} }
sacTRInv8x8 (p->lm.tmp1, p->lm.tmp1); sacTRInv8x8 (p->lm.tmp1, p->lm.tmp1);
sacTRISolve8x8(p->lm.tmp1, p->lm.Jte, dH); sacTRISolve8x8(p->lm.tmp1, p->lm.Jte, dH);
sacSub8x1 (newH, p->best.H, dH); sacSub8x1 (newH, p->best.H, dH);
sacCalcJacobianErrors(newH, p->arg.src, p->arg.dst, p->arg.inl, p->arg.N, sacCalcJacobianErrors(newH, p->arg.src, p->arg.dst, p->arg.inl, p->arg.N,
NULL, NULL, &newS); NULL, NULL, &newS);
gain = sacLMGain(dH, p->lm.Jte, S, newS, L);
/*printf("Lambda: %12.6f S: %12.6f newS: %12.6f Gain: %12.6f\n",
L, S, newS, gain);*/
/** /**
* If the new Sum of Square Errors (newS) corresponding to newH is * If the gain is positive (i.e., the new Sum of Square Errors (newS)
* lower than the previous one, save the current state and undamp * corresponding to newH is lower than the previous one (S) ), save
* sligthly (decrease L). Else damp more (increase L). * the current state and accept the new step dH.
*
* If the gain is below LM_GAIN_LO, damp more (increase L), even if the
* gain was positive. If the gain is above LM_GAIN_HI, damp less
* (decrease L). Otherwise the gain is left unchanged.
*/ */
if(newS < S){ if(gain < LM_GAIN_LO){
L *= 8;
if(L>1000.0f/FLT_EPSILON){
break;/* FIXME: Most naive termination criterion imaginable. */
}
}else if(gain > LM_GAIN_HI){
L *= 0.5;
}
if(gain > 0){
S = newS; S = newS;
memcpy(p->best.H, newH, sizeof(newH)); memcpy(p->best.H, newH, sizeof(newH));
sacCalcJacobianErrors(p->best.H, p->arg.src, p->arg.dst, p->arg.inl, p->arg.N, sacCalcJacobianErrors(p->best.H, p->arg.src, p->arg.dst, p->arg.inl, p->arg.N,
p->lm.JtJ, p->lm.Jte, &S); p->lm.JtJ, p->lm.Jte, &S);
/*printf("Error: %12.6f\n", S);*/
L *= 0.5;
if(L<FLT_EPSILON){
L = 1;
}
}else{
L *= 2.0;
if(L>1.0f/FLT_EPSILON){
break;
}
} }
} }
} }
...@@ -1816,35 +1812,36 @@ static inline void sacCalcJacobianErrors(const float* restrict H, ...@@ -1816,35 +1812,36 @@ static inline void sacCalcJacobianErrors(const float* restrict H,
} }
/** /**
* Compute the derivative of the rate of change of the SSE. * Compute the Levenberg-Marquardt "gain" obtained by the given step dH.
* *
* Inspired entirely by OpenCV's levmarq.cpp. To be reviewed. * Drawn from http://www2.imm.dtu.dk/documents/ftp/tr99/tr05_99.pdf.
*/ */
static inline float sacDs(const float (*JtJ)[8], static inline float sacLMGain(const float* dH,
const float* dH, const float* Jte,
const float* Jte){ const float S,
float tdH[8]; const float newS,
int i, j; const float lambda){
float dS = 0; float dS = S-newS;
float dL = 0;
int i;
/* Perform tdH = -JtJ*dH + 2*Jte. */ /* Compute h^t h... */
for(i=0;i<8;i++){ for(i=0;i<8;i++){
tdH[i] = 0; dL += dH[i]*dH[i];
for(j=0;j<8;j++){
tdH[i] -= JtJ[i][j] * dH[j];
}
tdH[i] += 2*Jte[i];
} }
/* Compute mu * h^t h... */
/* Perform dS = dH.dot(tdH). */ dL *= lambda;
/* Subtract h^t F'... */
for(i=0;i<8;i++){ for(i=0;i<8;i++){
dS += dH[i]*tdH[i]; dL += dH[i]*Jte[i];/* += as opposed to -=, since dH we compute is
opposite sign. */
} }
/* Multiply by 1/2... */
dL *= 0.5;
return dS; /* Return gain as S-newS / L0 - LH. */
return fabs(dL) < FLT_EPSILON ? dS : dS / dL;
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment