00001 #include "ndt_map/oc_tree.h"
00002 #include "ndt_map/ndt_cell.h"
00003 #include "ndt_map/lazy_grid.h"
00004 #include "pointcloud_vrml/pointcloud_utils.h"
00005 #include "Eigen/Eigen"
00006 #include <fstream>
00007 #include <omp.h>
00008
00009 #include <gsl/gsl_math.h>
00010 #include <gsl/gsl_deriv.h>
00011 #include <gsl/gsl_multimin.h>
00012
00013 namespace lslgeneric
00014 {
00015
00016 double transforms_objective_xyt (double &x, double &y, double&z, double&r,double&p,double &t, void *params) {
00017 double res = 0;
00018 TransformParams *tf = (TransformParams*) params;
00019 if (tf == NULL) return 0;
00020 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> G,Temp;
00021 Eigen::Matrix<double,4,4> I;
00022 I.setIdentity();
00023 Eigen::Vector3d et;
00024
00025 G = Eigen::Translation<double,3>(x,y,z)*
00026 Eigen::AngleAxis<double>(r,Eigen::Vector3d::UnitX())*
00027 Eigen::AngleAxis<double>(p,Eigen::Vector3d::UnitY())*
00028 Eigen::AngleAxis<double>(t,Eigen::Vector3d::UnitZ()) ;
00029
00030 for(int i=0; i<tf->fk.size(); i++)
00031 {
00032 Temp = tf->fk[i]*tf->rg[i].inverse();
00033 if((Temp.translation()).norm() + Temp.rotation().eulerAngles(0,1,2).norm() > 0.5)
00034 {
00035 std::cout<<"ignoring outlier at "<<i<<std::endl;
00036 continue;
00037 }
00038
00039 Temp = G*tf->rg[i]*G.inverse()*tf->fk[i].inverse();
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 Eigen::AngleAxis<double> ax;
00055 ax.fromRotationMatrix(Temp.rotation());
00056 res += Temp.translation().norm();
00057 }
00058
00059 return res;
00060 }
00061
00062 #if 0
00063
00064 double transforms_objective (const gsl_vector *v, void *params) {
00065 double res = 0, r=0;
00066 TransformParams *tf = (TransformParams*) params;
00067 if (tf == NULL) return 0;
00068 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> G,Temp;
00069 Eigen::Matrix<double,4,4> I;
00070 I.setIdentity();
00071 Eigen::Vector3d et;
00072
00073
00074
00075
00076
00077
00078 G = Eigen::Translation<double,3>(gsl_vector_get(v,0),gsl_vector_get(v,1),0)*
00079 Eigen::AngleAxis<double>(gsl_vector_get(v,2),Eigen::Vector3d::UnitZ()) ;
00080
00081 for(int i=0; i<tf->fk.size(); i++)
00082 {
00083 Temp = tf->fk[i]*tf->rg[i].inverse();
00084 if((Temp.translation()).norm() + Temp.rotation().eulerAngles(0,1,2).norm() > 0.2)
00085 {
00086 std::cout<<"ignoring outlier at "<<i<<std::endl;
00087 continue;
00088 }
00089
00090 Temp = G*tf->rg[i]*G.inverse()*tf->fk[i].inverse();
00091
00092
00093
00094 et = ((tf->rg[i].rotation())*(G.rotation().transpose())*(tf->fk[i].rotation().transpose()) - tf->rg[i].rotation())*G.translation() -
00095 tf->rg[i].rotation()*(G.rotation().transpose())*tf->fk[i].translation() + tf->rg[i].translation();
00096 et = (G*tf->fk[i]*G.inverse()).translation() - tf->rg[i].translation();
00097
00098 r = et.norm();
00099
00100
00101 res +=r;
00102 }
00103
00104 return res;
00105 }
00106 #endif
00107
00108 template <typename PointSource>
00109 void deallocate(std::vector<NDTCell<PointSource>* > &ndts) {
00110 for(unsigned int i=0; i<ndts.size(); i++)
00111 {
00112 if(ndts[i]!=NULL)
00113 delete ndts[i];
00114 }
00115 }
00116
00117
00118
00119 template <typename PointSource>
00120 bool NDTMatcherSequentialD2D<PointSource>::add_cloud( pcl::PointCloud<PointSource>& cloud,
00121 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor>& Tref)
00122 {
00123 pcs.push_back(cloud);
00124 LazyGrid<PointSource> prototype(current_resolution);
00125 NDTMap<PointSource> *NDT = new NDTMap<PointSource>( &prototype );
00126 NDT->loadPointCloud( cloud );
00127 NDT->computeNDTCells();
00128
00129 transforms.push_back(Tref);
00130 maps.push_back(NDT);
00131 }
00132
00133 template <typename PointSource>
00134 bool NDTMatcherSequentialD2D<PointSource>::match_all(Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor>& RES, bool useInitialGuess)
00135 {
00136
00137 double __res[] = {0.1,0.2};
00138
00139 std::vector<double> resolutions (__res, __res+sizeof(__res)/sizeof(double));
00140 std::vector<Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor>,
00141 Eigen::aligned_allocator<Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> > > reg_transforms, rel_transforms, err_transforms;
00142
00143 lslgeneric::NDTMatcherD2D<PointSource,PointSource> matcherD2D(false, false, resolutions);
00144 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> Tout, tempT;
00145 Tout.setIdentity();
00146
00147 char fname[50];
00148 FILE *fout;
00149
00150 for(int i=1; i<pcs.size(); ++i)
00151 {
00152 Tout.setIdentity();
00153 Tout = (transforms[i-1].inverse()*transforms[i]);
00154 std::cout<<Tout.matrix()<<std::endl;
00155 bool ret = matcherD2D.match(pcs[i-1],pcs[i],Tout,true);
00156 reg_transforms.push_back(Tout);
00157
00158 snprintf(fname,49,"c_offset_%02d.wrl",i);
00159 fout = fopen(fname,"w");
00160 fprintf(fout,"#VRML V2.0 utf8\n");
00161 lslgeneric::writeToVRML<PointSource>(fout,pcs[i-1],Eigen::Vector3d(1,0,0));
00162
00163 pcl::PointCloud<PointSource> tmp1 = pcs[i];
00164 tempT = (transforms[i-1].inverse()*transforms[i]);
00165 lslgeneric::transformPointCloudInPlace<PointSource>(tempT,tmp1);
00166 lslgeneric::writeToVRML<PointSource>(fout,tmp1,Eigen::Vector3d(1,1,1));
00167 pcl::PointCloud<PointSource> tmp2 = pcs[i];
00168 lslgeneric::transformPointCloudInPlace<PointSource>(Tout,tmp2);
00169 lslgeneric::writeToVRML<PointSource>(fout,tmp2,Eigen::Vector3d(0,1,0));
00170 fclose(fout);
00171
00172
00173
00174 }
00175
00176 for(int i=1; i<transforms.size(); ++i)
00177 {
00178 std::cout<<"rel: "<<i<<std::endl;
00179 rel_transforms.push_back( (transforms[i-1].inverse()*transforms[i]));
00180 std::cout<<rel_transforms[i-1].translation().transpose()<<" "<<rel_transforms[i-1].rotation().eulerAngles(0,1,2).transpose()<<std::endl;
00181 std::cout<<reg_transforms[i-1].translation().transpose()<<" "<<reg_transforms[i-1].rotation().eulerAngles(0,1,2).transpose()<<std::endl;
00182 }
00183 #if 0
00184 Eigen::Vector3d v,x;
00185 Eigen::Matrix3d M, U, L;
00186
00187
00188 for(int i=1; i<transforms.size(); ++i)
00189 {
00190 Tout.setIdentity();
00191 U = (rel_transforms[i-1].rotation()).llt().matrixL();
00192 L = (reg_transforms[i-1].rotation()).llt().matrixL();
00193 Tout.rotate(U.transpose()*L);
00194 v = rel_transforms[i-1].translation() - Tout.rotation().transpose()*(reg_transforms[i-1].translation());
00195 M = Tout.rotation().transpose()*reg_transforms[i-1].rotation() - Eigen::Matrix3d::Identity();
00196
00197 Eigen::JacobiSVD<Eigen::Matrix3d> svd(M, Eigen::ComputeFullU | Eigen::ComputeFullV);
00198 x = svd.solve(v);
00199 std::cout<<"M = "<<M<<std::endl;
00200 std::cout<<"v = "<<v.transpose()<<std::endl;
00201 std::cout<<"x = "<<x.transpose()<<std::endl;
00202 Tout.translation() = x;
00203
00204 std::cout<<Tout.translation().transpose()<<" "<<Tout.rotation().eulerAngles(0,1,2).transpose()<<std::endl;
00205 err_transforms.push_back(Tout);
00206 }
00207
00208 #endif
00209
00210 #if 0
00211 TransformParams tf;
00212 tf.fk = rel_transforms;
00213 tf.rg = reg_transforms;
00214
00215 const gsl_multimin_fminimizer_type *T =
00216 gsl_multimin_fminimizer_nmsimplex2;
00217 gsl_multimin_fminimizer *s = NULL;
00218 gsl_vector *ss, *x;
00219 gsl_multimin_function minex_func;
00220
00221 size_t iter = 0;
00222 int status;
00223 double size;
00224
00225
00226 x = gsl_vector_alloc (3);
00227 gsl_vector_set_all (x, 0.0);
00228
00229
00230
00231
00232
00233 ss = gsl_vector_alloc (3);
00234 gsl_vector_set_all (ss, 1);
00235
00236
00237 minex_func.n = 3;
00238 minex_func.f = transforms_objective;
00239 minex_func.params = &tf;
00240
00241 s = gsl_multimin_fminimizer_alloc (T, 3);
00242 gsl_multimin_fminimizer_set (s, &minex_func, x, ss);
00243
00244 do
00245 {
00246 iter++;
00247 status = gsl_multimin_fminimizer_iterate(s);
00248
00249 if (status)
00250 break;
00251
00252 size = gsl_multimin_fminimizer_size (s);
00253 status = gsl_multimin_test_size (size, 1e-2);
00254
00255 if (status == GSL_SUCCESS)
00256 {
00257 printf ("converged to minimum at\n");
00258 }
00259
00260 printf ("%5d %10.3e %10.3e %10.3ef() = %7.3f size = %.3f\n",
00261 iter,
00262 gsl_vector_get (s->x, 0),
00263 gsl_vector_get (s->x, 1),
00264 gsl_vector_get (s->x, 2),
00265
00266
00267
00268 s->fval, size);
00269 }
00270 while (status == GSL_CONTINUE && iter < 200);
00271 RES = Eigen::Translation<double,3>(gsl_vector_get(s->x,0),gsl_vector_get(s->x,1),0)*
00272
00273
00274 Eigen::AngleAxis<double>(gsl_vector_get(s->x,2),Eigen::Vector3d::UnitZ()) ;
00275
00276 gsl_vector_free(x);
00277 gsl_vector_free(ss);
00278 gsl_multimin_fminimizer_free (s);
00279 #endif
00280
00281 TransformParams tf;
00282 tf.fk = rel_transforms;
00283 tf.rg = reg_transforms;
00284
00285 double res_min = 0.004, res_max = 0.01;
00286 double res = res_max;
00287
00288 double xmin = -0.1, xmax =0.1;
00289 double ymin = -0.1, ymax =0.1;
00290 double zmin = -0.1, zmax =0.1;
00291 double rmin = -0.1, rmax =0.1;
00292 double pmin = -0.1, pmax =0.1;
00293 double tmin = -0.1, tmax =0.1;
00294
00295 double xx=0,yy=0,zz=0,rr=0,pp=0,tt=0;
00296 int ctr =0;
00297 double score_min = INT_MAX;
00298 double score_here;
00299
00300 double y = 0;
00301
00302 double r=0;
00303 double p=0;
00304 while ( res > res_min) {
00305 for(double x=xmin; x<xmax; x+=res) {
00306
00307 for(double z=zmin; z<zmax; z+=res) {
00308
00309
00310 for(double t=tmin; t<tmax; t+=res) {
00311 score_here = transforms_objective_xyt (x,y,z,r,p,t,(void*)&tf);
00312 if(score_here < score_min) {
00313 xx = x;
00314 yy = y;
00315 zz = z;
00316 rr = r;
00317 pp = p;
00318 tt = t;
00319 score_min = score_here;
00320 std::cout<<"new min of "<<score_here<<" at "<<x<<" "<<y<<" "<<" "<<z<<" "<<r<<" "<<p<<" "<<t<<std::endl;
00321 }
00322
00323 ctr++;
00324 }
00325
00326
00327 }
00328
00329 }
00330 res = res/2;
00331 xmin = xx-10*res;
00332 ymin = yy-10*res;
00333 zmin = zz-10*res;
00334 rmin = rr-2*res;
00335 pmin = pp-2*res;
00336 tmin = tt-10*res;
00337 xmax = xx+10*res;
00338 ymax = yy+10*res;
00339 zmax = zz+10*res;
00340 rmax = rr+2*res;
00341 pmax = pp+2*res;
00342 tmax = tt+10*res;
00343 std::cout<<"going to RES "<<res<<" bounds +/- "<<xmax<<" "<<ymax<<" "<<zmax<<" "<<rmax<<" "<<pmax<<" "<<tmax<<std::endl;
00344 }
00345
00346 std::cout<<"FINAL min at "<<score_min<<" at "<<xx<<" "<<yy<<" "<<zz<<" "<<rr<<" "<<pp<<" "<<tt<<std::endl;
00347 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> RES2;
00348 RES = Eigen::Translation<double,3>(xx,yy,zz)*
00349 Eigen::AngleAxis<double>(tt,Eigen::Vector3d::UnitZ()) ;
00350
00351 for(int i=1; i<pcs.size(); ++i)
00352 {
00353 snprintf(fname,49,"calib_offset_%02d.wrl",i);
00354 fout = fopen(fname,"w");
00355 fprintf(fout,"#VRML V2.0 utf8\n");
00356 pcl::PointCloud<PointSource> tmp0 = pcs[i-1];
00357
00358
00359
00360 tempT = transforms[i-1]*RES;
00361 lslgeneric::transformPointCloudInPlace<PointSource>(tempT,tmp0);
00362 lslgeneric::writeToVRML<PointSource>(fout,tmp0,Eigen::Vector3d(1,0,0));
00363 pcl::PointCloud<PointSource> tmp1 = pcs[i];
00364
00365 tempT = transforms[i]*RES;
00366 lslgeneric::transformPointCloudInPlace<PointSource>(tempT,tmp1);
00367 lslgeneric::writeToVRML<PointSource>(fout,tmp1,Eigen::Vector3d(1,1,1));
00368 tmp0 = pcs[i-1];
00369 tempT = transforms[i-1];
00370 lslgeneric::transformPointCloudInPlace<PointSource>(tempT,tmp0);
00371 lslgeneric::writeToVRML<PointSource>(fout,tmp0,Eigen::Vector3d(1,1,0));
00372 tmp1 = pcs[i];
00373 tempT = transforms[i];
00374 lslgeneric::transformPointCloudInPlace<PointSource>(tempT,tmp1);
00375 lslgeneric::writeToVRML<PointSource>(fout,tmp1,Eigen::Vector3d(1,0,1));
00376 fclose(fout);
00377
00378
00379 }
00380 }
00381
00382 #if 0
00383 template <typename PointSource>
00384 bool NDTMatcherSequentialD2D<PointSource>::match_all(Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor>& T, bool useInitialGuess)
00385 {
00386
00387
00388 bool convergence = false;
00389
00390 double DELTA_SCORE = 10e-3*current_resolution;
00391
00392
00393 int itr_ctr = 0;
00394
00395 double step_size = 1;
00396 Eigen::Matrix<double,6,1> pose_increment_v, pose_accum, scg;
00397 Eigen::MatrixXd Hessian(6,6), score_gradient(6,1);
00398 Eigen::MatrixXd Hessian_loc(6,6), score_gradient_loc(6,1);
00399
00400 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> TR, Tloc;
00401 Eigen::Vector3d transformed_vec, mean;
00402 bool ret = true;
00403 if(!useInitialGuess)
00404 {
00405 T.setIdentity();
00406 }
00407
00408 Eigen::Array<double,6,1> weights;
00409 Eigen::Quaterniond qsum, qloc;
00410 Eigen::Vector4d qsum_vec, qloc_vec;
00411
00412
00413 while(!convergence)
00414 {
00415 pose_accum.setZero();
00416 double score_here = 0;
00417 int nsuccess =0;
00418 for(int i=0; i<maps.size(); i++)
00419 {
00420 TR.setIdentity();
00421 Hessian.setZero();
00422 score_gradient.setZero();
00423 Tloc = transforms[i]*T;
00424 std::vector<NDTCell<PointSource>*> nextNDT = maps[i]->pseudoTransformNDT(Tloc);
00425 std::vector<NDTCell<PointSource>*> fixedNDT;
00426
00427 for(int j=i-3; j<i+3; j++)
00428 {
00429 if(j < 0 || j >= maps.size()) continue;
00430 if(i == j) continue;
00431 Tloc = transforms[j]*T;
00432 std::vector<NDTCell<PointSource>*> locNDT = maps[j]->pseudoTransformNDT(Tloc);
00433 fixedNDT.insert(fixedNDT.begin(), locNDT.begin(), locNDT.end());
00434 }
00435 score_here += derivativesNDT(nextNDT,fixedNDT,score_gradient,Hessian,true);
00436
00437 scg = score_gradient;
00438 Eigen::SelfAdjointEigenSolver<Eigen::Matrix<double,6,6> > Sol (Hessian);
00439 Eigen::Matrix<double,6,1> evals = Sol.eigenvalues().real();
00440 double minCoeff = evals.minCoeff();
00441 double maxCoeff = evals.maxCoeff();
00442 if(minCoeff < 0 )
00443 {
00444 Eigen::Matrix<double,6,6> evecs = Sol.eigenvectors().real();
00445 double regularizer = 0.01*maxCoeff - minCoeff;
00446 Eigen::Matrix<double,6,1> reg;
00447
00448 reg<<regularizer,regularizer,regularizer,regularizer,regularizer,regularizer;
00449 evals += reg;
00450 Eigen::Matrix<double,6,6> Lam;
00451 Lam = evals.asDiagonal();
00452 Hessian = evecs*Lam*(evecs.transpose());
00453 std::cerr<<"regularizing\n";
00454 }
00455
00456
00457
00458
00459
00460 if (score_gradient.norm()<= DELTA_SCORE)
00461 {
00462
00463 std::cout<<"\%gradient vanished\n";
00464 deallocate(nextNDT);
00465 deallocate(fixedNDT);
00466 continue;
00467 }
00468
00469 pose_increment_v = -Hessian.ldlt().solve(score_gradient);
00470 double dginit = pose_increment_v.dot(scg);
00471 if(dginit > 0)
00472 {
00473 std::cout<<"\%can't decrease in this direction any more, done \n";
00474 deallocate(nextNDT);
00475 deallocate(fixedNDT);
00476 continue;
00477 }
00478
00479 step_size = lineSearchMT(pose_increment_v,nextNDT,fixedNDT);
00480
00481 pose_increment_v = step_size*pose_increment_v;
00482 std::cout<<"\%iteration "<<itr_ctr<<" pose "<<(pose_increment_v.transpose())<<" score "<<score_here<<" step "<<step_size<<std::endl;
00483 if(pose_increment_v.norm() > 1) {
00484 deallocate(nextNDT);
00485 deallocate(fixedNDT);
00486 continue;
00487 }
00488 qloc = Eigen::AngleAxis<double>(pose_increment_v(3),Eigen::Vector3d::UnitX()) *
00489 Eigen::AngleAxis<double>(pose_increment_v(4),Eigen::Vector3d::UnitY()) *
00490 Eigen::AngleAxis<double>(pose_increment_v(5),Eigen::Vector3d::UnitZ()) ;
00491
00492 qloc_vec(0) = qloc.x();
00493 qloc_vec(1) = qloc.y();
00494 qloc_vec(2) = qloc.z();
00495 qloc_vec(3) = qloc.w();
00496 qsum_vec = qsum_vec+qloc_vec;
00497 std::cout<<"Q "<<qsum_vec.transpose()<<"--"<<qloc_vec.transpose()<<std::endl;
00498 pose_accum += pose_increment_v;
00499 nsuccess ++;
00500
00501 deallocate(nextNDT);
00502 deallocate(fixedNDT);
00503
00504 }
00505 pose_accum /= nsuccess;
00506 qsum_vec = qsum_vec/nsuccess;
00507
00508 std::cout<<"qs "<<qsum_vec.transpose()<<std::endl;
00509 qsum.x() = qsum_vec(0);
00510 qsum.y() = qsum_vec(1);
00511 qsum.z() = qsum_vec(2);
00512 qsum.w() = qsum_vec(3);
00513 qsum.normalize();
00514
00515 TR.setIdentity();
00516 TR = Eigen::Translation<double,3>(pose_accum(0),pose_accum(1),0)*qsum;
00517
00518 T = TR*T;
00519 std::cout<<"incr(:,"<<itr_ctr+1<<") = ["<<TR.translation().transpose()<<" "<<TR.rotation().eulerAngles(0,1,2).transpose()<<"]';\n";
00520 std::cout<<"pose(:,"<<itr_ctr+2<<") = ["<<T.translation().transpose()<<" "<<T.rotation().eulerAngles(0,1,2).transpose()<<"]';\n";
00521
00522 if(itr_ctr>0)
00523 {
00524 convergence = ((TR.translation().norm() + TR.rotation().eulerAngles(0,1,2).norm()) < DELTA_SCORE);
00525
00526 }
00527 if(itr_ctr>ITR_MAX)
00528 {
00529 convergence = true;
00530 ret = false;
00531 }
00532 itr_ctr++;
00533
00534
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553 return ret;
00554 }
00555 #endif
00556
00557
00558 template <typename PointSource>
00559 bool NDTMatcherSequentialD2D<PointSource>::update_gradient_hessian_local(
00560 Eigen::MatrixXd &score_gradient,
00561 Eigen::MatrixXd &Hessian,
00562 const Eigen::Vector3d & x,
00563 const Eigen::Matrix3d & B,
00564 const double &likelihood,
00565 const Eigen::Matrix<double,3,6> &_Jest,
00566 const Eigen::Matrix<double,18,6> &_Hest,
00567 const Eigen::Matrix<double,3,18> &_Zest,
00568 const Eigen::Matrix<double,18,18> &_ZHest,
00569 bool computeHessian)
00570 {
00571
00572
00573
00574 Eigen::Matrix<double,6,1> _xtBJ, _xtBZBx, _Q;
00575
00576 Eigen::Matrix<double,6,6> _xtBZBJ, _xtBH, _xtBZBZBx, _xtBZhBx;
00577 Eigen::Matrix<double,1,3> _TMP1, _xtB;
00578
00579 _xtBJ.setZero();
00580 _xtBZBx.setZero();
00581 _Q.setZero();
00582 _xtBZBJ.setZero();
00583 _xtBH.setZero();
00584 _xtBZBZBx.setZero();
00585 _xtBZhBx.setZero();
00586 _TMP1.setZero();
00587 _xtB.setZero();
00588
00589 _xtB = x.transpose()*B;
00590 _xtBJ = _xtB*_Jest;
00591
00592 for(unsigned int i=0; i<6; i++)
00593 {
00594 _TMP1 = _xtB*_Zest.block<3,3>(0,3*i)*B;
00595 _xtBZBx(i) = _TMP1*x;
00596 if(computeHessian)
00597 {
00598 _xtBZBJ.col(i) = (_TMP1*_Jest).transpose();
00599 for(unsigned int j=0; j<6; j++)
00600 {
00601 _xtBH(i,j) = _xtB*_Hest.block<3,1>(3*i,j);
00602 _xtBZBZBx(i,j) = _TMP1*_Zest.block<3,3>(0,3*j)*B*x;
00603 _xtBZhBx(i,j) = _xtB*_ZHest.block<3,3>(3*i,3*j)*B*x;
00604 }
00605 }
00606 }
00607 _Q = 2*_xtBJ-_xtBZBx;
00608 double factor = -(lfd2/2)*likelihood;
00609 score_gradient += _Q*factor;
00610
00611 if(computeHessian)
00612 {
00613 Hessian += factor*(2*_Jest.transpose()*B*_Jest+2*_xtBH -_xtBZhBx -2*_xtBZBJ.transpose()
00614 -2*_xtBZBJ +_xtBZBZBx +_xtBZBZBx.transpose() -lfd2*_Q*_Q.transpose()/2 );
00615
00616 }
00617 return true;
00618 }
00619
00620
00621 template <typename PointSource>
00622 void NDTMatcherSequentialD2D<PointSource>::computeDerivativesLocal(Eigen::Vector3d &x, Eigen::Matrix3d C1,
00623 Eigen::Matrix<double,3,6> &_Jest,
00624 Eigen::Matrix<double,18,6> &_Hest,
00625 Eigen::Matrix<double,3,18> &_Zest,
00626 Eigen::Matrix<double,18,18> &_ZHest,
00627 bool computeHessian)
00628 {
00629
00630 _Jest(0,4) = x(2);
00631 _Jest(0,5) = -x(1);
00632 _Jest(1,3) = -x(2);
00633 _Jest(1,5) = x(0);
00634 _Jest(2,3) = x(1);
00635 _Jest(2,4) = -x(0);
00636 Eigen::Vector3d a,b,c,d,e,f;
00637 a<<0,-x(1),-x(2);
00638 b<<0,x(0),0;
00639 c<<0,0,x(0);
00640 d<<-x(0),0,-x(2);
00641 e<<0,0,x(1);
00642 f<<-x(0),-x(1),0;
00643
00644 Eigen::Matrix3d myBlock;
00645
00646 myBlock<<
00647 0, -C1(0,2), C1(0,1),
00648 -C1(0,2), -2*C1(1,2), -C1(2,2) + C1(1,1),
00649 C1(0,1), -C1(2,2) + C1(1,1), 2*C1(1,2);
00650 _Zest.block<3,3>(0,9) = myBlock;
00651 myBlock<<
00652 2*C1(0,2), C1(1,2), -C1(0,0) + C1(2,2),
00653 C1(1,2), 0, -C1(0,1),
00654 -C1(0,0) + C1(2,2), -C1(0,1), -2*C1(0,2);
00655 _Zest.block<3,3>(0,12) = myBlock;
00656 myBlock<<
00657 -2*C1(0,1), -C1(1,1) + C1(0,0), -C1(1,2),
00658 -C1(1,1) + C1(0,0), 2*C1(0,1), C1(0,2),
00659 -C1(1,2), C1(0,2), 0;
00660 _Zest.block<3,3>(0,15) = myBlock;
00661
00662 if(computeHessian)
00663 {
00664
00665 _Hest.block<3,1>(9,3) = a;
00666 _Hest.block<3,1>(12,3) = b;
00667 _Hest.block<3,1>(15,3) = c;
00668 _Hest.block<3,1>(9,4) = b;
00669 _Hest.block<3,1>(12,4) = d;
00670 _Hest.block<3,1>(15,4) = e;
00671 _Hest.block<3,1>(9,5) = c;
00672 _Hest.block<3,1>(12,5) = e;
00673 _Hest.block<3,1>(15,5) = f;
00674
00675
00676 myBlock<<
00677 0, -C1(0,1), -C1(0,2),
00678 -C1(0,1), 2*C1(2,2) - 2*C1(1,1), -4*C1(1,2),
00679 -C1(0,2), -4*C1(1,2), 2*C1(1,1) - 2*C1(2,2);
00680 _ZHest.block<3,3>(9,9) = myBlock;
00681
00682 myBlock<<
00683 0, C1(0,0) - C1(2,2), C1(1,2),
00684 C1(0,0) - C1(2,2), 2*C1(0,1), 2*C1(0,2),
00685 C1(1,2), 2*C1(0,2), -2*C1(0,1);
00686 _ZHest.block<3,3>(9,12) = myBlock;
00687
00688 myBlock<<
00689 0, C1(1,2), C1(0,0) - C1(1,1),
00690 C1(1,2), -2*C1(0,2), 2*C1(0,1),
00691 C1(0,0) - C1(1,1), 2*C1(0,1), 2*C1(0,2);
00692 _ZHest.block<3,3>(9,15) = myBlock;
00693
00694 myBlock<<
00695 2*C1(2,2) - 2*C1(0,0), -C1(0,1), -4*C1(0,2),
00696 -C1(0,1), 0, -C1(1,2),
00697 -4*C1(0,2), -C1(1,2), 2*C1(0,0) - 2*C1(2,2);
00698 _ZHest.block<3,3>(12,12) = myBlock;
00699
00700 myBlock<<
00701 -2*C1(1,2), C1(0,2), 2*C1(0,1),
00702 C1(0,2), 0, C1(1,1) - C1(0,0),
00703 2*C1(0,1), C1(1,1) - C1(0,0), 2*C1(1,2);
00704 _ZHest.block<3,3>(12,15) = myBlock;
00705
00706 myBlock<<
00707 2*C1(1,1) - 2*C1(0,0), -4*C1(0,1), -C1(0,2),
00708 -4*C1(0,1), 2*C1(0,0) - 2*C1(1,1), -C1(1,2),
00709 -C1(0,2), -C1(1,2), 0;
00710 _ZHest.block<3,3>(15,15)= myBlock;
00711
00712 _ZHest.block<3,3>(12,9) = _ZHest.block<3,3>(9,12);
00713 _ZHest.block<3,3>(15,9) = _ZHest.block<3,3>(9,15);
00714 _ZHest.block<3,3>(15,12)= _ZHest.block<3,3>(12,15);
00715 }
00716 }
00717
00718
00719 template <typename PointSource>
00720
00721 double NDTMatcherSequentialD2D<PointSource>::derivativesNDT(
00722 const std::vector<NDTCell<PointSource>*> &sourceNDT,
00723 const std::vector<NDTCell<PointSource>*> &targetNDT,
00724 Eigen::MatrixXd &score_gradient,
00725 Eigen::MatrixXd &Hessian,
00726 bool computeHessian
00727 )
00728 {
00729
00730
00731 struct timeval tv_start, tv_end;
00732 double score_here = 0;
00733 int n_dimensions = score_gradient.rows();
00734
00735 gettimeofday(&tv_start,NULL);
00736 score_gradient.setZero();
00737 Hessian.setZero();
00738
00739 Eigen::MatrixXd score_gradient_omp;
00740 Eigen::MatrixXd score_here_omp;
00741 Eigen::MatrixXd Hessian_omp;
00742
00743 #define n_threads 8
00744
00745
00746 score_gradient_omp.resize(n_dimensions,n_threads);
00747 score_here_omp.resize(1,n_threads);
00748 Hessian_omp.resize(n_dimensions,n_dimensions*n_threads);
00749
00750 score_gradient_omp.setZero();
00751 score_here_omp.setZero();
00752 Hessian_omp.setZero();
00753
00754
00755 #pragma omp parallel num_threads(n_threads)
00756 {
00757 #pragma omp for
00758 for(unsigned int i=0; i<sourceNDT.size(); i++)
00759 {
00760 PointSource point;
00761 Eigen::Vector3d transformed;
00762 Eigen::Vector3d meanMoving, meanFixed;
00763 Eigen::Matrix3d CMoving, CFixed, CSum, Cinv, R;
00764 Eigen::MatrixXd score_gradient_omp_loc(n_dimensions,1);
00765 Eigen::MatrixXd Hessian_omp_loc(n_dimensions,n_dimensions);
00766 Eigen::Matrix<double,3,6> _Jest;
00767 Eigen::Matrix<double,18,6> _Hest;
00768 Eigen::Matrix<double,3,18> _Zest;
00769 Eigen::Matrix<double,18,18> _ZHest;
00770 double score_here_loc=0;
00771 int thread_id = omp_get_thread_num();
00772 NDTCell<PointSource> *cell;
00773 bool exists = false;
00774 double det = 0;
00775
00776
00777 score_gradient_omp_loc.setZero();
00778 Hessian_omp_loc.setZero();
00779 _Jest.setZero();
00780 _Jest.block<3,3>(0,0).setIdentity();
00781 _Hest.setZero();
00782 _Zest.setZero();
00783 _ZHest.setZero();
00784
00785 meanMoving = sourceNDT[i]->getMean();
00786 CMoving= sourceNDT[i]->getCov();
00787 computeDerivativesLocal(meanMoving, CMoving, _Jest, _Hest, _Zest, _ZHest, computeHessian);
00788
00789 point.x = meanMoving(0);
00790 point.y = meanMoving(1);
00791 point.z = meanMoving(2);
00792 std::vector<NDTCell<PointSource>*> cells = targetNDT;
00793 for(int j=0; j<cells.size(); j++)
00794 {
00795 cell = cells[j];
00796 if(cell == NULL)
00797 {
00798 continue;
00799 }
00800 if(cell->hasGaussian_)
00801 {
00802 transformed = meanMoving - cell->getMean();
00803 if(transformed.norm() > 8*current_resolution) continue;
00804 CFixed = cell->getCov();
00805 CSum = (CFixed+CMoving);
00806 CSum.computeInverseAndDetWithCheck(Cinv,det,exists);
00807 if(!exists)
00808 {
00809 continue;
00810 }
00811 double l = (transformed).dot(Cinv*(transformed));
00812 if(l*0 != 0)
00813 {
00814 continue;
00815 }
00816
00817 double sh = -lfd1*(exp(-lfd2*l/2));
00818 if(!update_gradient_hessian_local(score_gradient_omp_loc,Hessian_omp_loc,transformed, Cinv, sh,
00819 _Jest, _Hest, _Zest, _ZHest, computeHessian))
00820 {
00821 continue;
00822 }
00823 score_here_loc += sh;
00824 cell = NULL;
00825 }
00826 }
00827
00828 score_gradient_omp.col(thread_id) += score_gradient_omp_loc;
00829 Hessian_omp.block(0,n_dimensions*thread_id,n_dimensions,n_dimensions) += Hessian_omp_loc;
00830 score_here_omp(0,thread_id) += score_here_loc;
00831
00832 }
00833 }
00834
00835
00836
00837 score_gradient = score_gradient_omp.rowwise().sum();
00838 score_here = score_here_omp.sum();
00839 if(computeHessian)
00840 {
00841
00842 for(int i=0; i<n_threads; ++i)
00843 {
00844 Hessian += Hessian_omp.block(0,n_dimensions*i,n_dimensions,n_dimensions);
00845 }
00846 }
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886 gettimeofday(&tv_end,NULL);
00887
00888 double time_load = (tv_end.tv_sec-tv_start.tv_sec)*1000.+(tv_end.tv_usec-tv_start.tv_usec)/1000.;
00889
00890 return score_here;
00891 }
00892
00893
00894 template <typename PointSource>
00895 double NDTMatcherSequentialD2D<PointSource>::lineSearchMT(
00896 Eigen::Matrix<double,6,1> &increment,
00897 std::vector<NDTCell<PointSource>*> &sourceNDT,
00898 std::vector<NDTCell<PointSource>*> &targetNDT
00899 )
00900 {
00901
00902
00903 double stp = 1.0;
00904 double recoverystep = 0.1;
00905 double dginit = 0.0;
00906 double ftol = 0.11111;
00907 double gtol = 0.99999;
00908 double stpmax = 4.0;
00909 double stpmin = 0.001;
00910 int maxfev = 40;
00911 double xtol = 0.01;
00912
00913
00914 std::vector<NDTCell<PointSource>*> sourceNDTHere;
00915 double score_init = 0.0;
00916
00917 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> ps;
00918 ps.setIdentity();
00919
00920 Eigen::Matrix<double,6,1> scg_here;
00921 Eigen::MatrixXd pincr(6,1), score_gradient_here(6,1);
00922 Eigen::MatrixXd pseudoH(6,6);
00923 Eigen::Vector3d eulerAngles;
00925
00926 int info = 0;
00927 int infoc = 1;
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942 score_gradient_here.setZero();
00943 score_init = derivativesNDT(sourceNDT,targetNDT,score_gradient_here,pseudoH,false);
00944 scg_here = score_gradient_here;
00945 dginit = increment.dot(scg_here);
00946
00947
00948 if (dginit >= 0.0)
00949 {
00950 std::cout << "MoreThuente::cvsrch - wrong direction (dginit = " << dginit << ")" << std::endl;
00951
00952
00953
00954 increment = -increment;
00955 dginit = -dginit;
00956
00957 if (dginit >= 0.0)
00958 {
00959 for(unsigned int i=0; i<sourceNDTHere.size(); i++)
00960 {
00961 if(sourceNDTHere[i]!=NULL)
00962 delete sourceNDTHere[i];
00963 }
00964 return recoverystep;
00965 }
00966 }
00967 else
00968 {
00969
00970 }
00971
00972
00973
00974 bool brackt = false;
00975 bool stage1 = true;
00976 int nfev = 0;
00977 double dgtest = ftol * dginit;
00978 double width = stpmax - stpmin;
00979 double width1 = 2 * width;
00980
00981
00982
00983 double finit = 0.0;
00984 finit = score_init;
00985
00986
00987
00988
00989
00990
00991
00992
00993 double stx = 0.0;
00994 double fx = finit;
00995 double dgx = dginit;
00996 double sty = 0.0;
00997 double fy = finit;
00998 double dgy = dginit;
00999
01000
01001
01002
01003
01004
01005
01006
01007 double stmin, stmax;
01008 double fm, fxm, fym, dgm, dgxm, dgym;
01009
01010 while (1)
01011 {
01012
01013
01014 if (brackt)
01015 {
01016 stmin = MoreThuente::min(stx, sty);
01017 stmax = MoreThuente::max(stx, sty);
01018 }
01019 else
01020 {
01021 stmin = stx;
01022 stmax = stp + 4 * (stp - stx);
01023 }
01024
01025
01026 stp = MoreThuente::max(stp, stpmin);
01027 stp = MoreThuente::min(stp, stpmax);
01028
01029
01030
01031
01032 if ((brackt && ((stp <= stmin) || (stp >= stmax))) ||
01033 (nfev >= maxfev - 1) || (infoc == 0) ||
01034 (brackt && (stmax - stmin <= xtol * stmax)))
01035 {
01036 stp = stx;
01037 }
01038
01039
01040
01042
01043 pincr = stp*increment;
01044
01045 ps = Eigen::Translation<double,3>(pincr(0),pincr(1),pincr(2))*
01046 Eigen::AngleAxisd(pincr(3),Eigen::Vector3d::UnitX())*
01047 Eigen::AngleAxisd(pincr(4),Eigen::Vector3d::UnitY())*
01048 Eigen::AngleAxisd(pincr(5),Eigen::Vector3d::UnitZ());
01049
01050 for(unsigned int i=0; i<sourceNDTHere.size(); i++)
01051 {
01052 if(sourceNDTHere[i]!=NULL)
01053 delete sourceNDTHere[i];
01054 }
01055 sourceNDTHere.clear();
01056 for(unsigned int i=0; i<sourceNDT.size(); i++)
01057 {
01058 NDTCell<PointSource> *cell = sourceNDT[i];
01059 if(cell!=NULL)
01060 {
01061 Eigen::Vector3d mean = cell->getMean();
01062 Eigen::Matrix3d cov = cell->getCov();
01063 mean = ps*mean;
01064 cov = ps.rotation()*cov*ps.rotation().transpose();
01065 NDTCell<PointSource>* nd = (NDTCell<PointSource>*)cell->copy();
01066 nd->setMean(mean);
01067 nd->setCov(cov);
01068 sourceNDTHere.push_back(nd);
01069 }
01070 }
01071
01072 double f = 0.0;
01073 score_gradient_here.setZero();
01074
01075
01076
01077
01078
01079
01080
01081
01082 f = derivativesNDT(sourceNDTHere,targetNDT,score_gradient_here,pseudoH,false);
01083
01084
01085
01086
01087
01088
01089 double dg = 0.0;
01090 scg_here = score_gradient_here;
01091 dg = increment.dot(scg_here);
01092
01093
01094
01095
01096 nfev ++;
01097
01099
01100
01101
01102 double ftest1 = finit + stp * dgtest;
01103
01104
01105
01106
01107 if ((brackt && ((stp <= stmin) || (stp >= stmax))) || (infoc == 0))
01108 info = 6;
01109
01110 if ((stp == stpmax) && (f <= ftest1) && (dg <= dgtest))
01111 info = 5;
01112
01113 if ((stp == stpmin) && ((f > ftest1) || (dg >= dgtest)))
01114 info = 4;
01115
01116 if (nfev >= maxfev)
01117 info = 3;
01118
01119 if (brackt && (stmax-stmin <= xtol*stmax))
01120 info = 2;
01121
01122
01123 bool sufficientDecreaseTest = false;
01124 sufficientDecreaseTest = (f <= ftest1);
01125
01126
01127
01128
01129 if ((sufficientDecreaseTest) && (fabs(dg) <= gtol*(-dginit)))
01130 info = 1;
01131
01132 if (info != 0)
01133 {
01134 if (info != 1)
01135 {
01136
01137
01138
01139
01140 stp = recoverystep;
01141
01142
01143
01144
01145
01146 }
01147 else
01148 {
01149
01150 }
01151
01152
01153
01154
01155
01156 for(unsigned int i=0; i<sourceNDTHere.size(); i++)
01157 {
01158 if(sourceNDTHere[i]!=NULL)
01159 delete sourceNDTHere[i];
01160 }
01161
01162 return stp;
01163
01164 }
01165
01166
01167
01168
01169
01170
01171
01172 if (stage1 && (f <= ftest1) && (dg >= MoreThuente::min(ftol, gtol) * dginit))
01173 {
01174 stage1 = false;
01175 }
01176
01177
01178
01179
01180
01181
01182
01183 if (stage1 && (f <= fx) && (f > ftest1))
01184 {
01185
01186
01187
01188 fm = f - stp * dgtest;
01189 fxm = fx - stx * dgtest;
01190 fym = fy - sty * dgtest;
01191 dgm = dg - dgtest;
01192 dgxm = dgx - dgtest;
01193 dgym = dgy - dgtest;
01194
01195
01196
01197
01198
01199 infoc = MoreThuente::cstep(stx,fxm,dgxm,sty,fym,dgym,stp,fm,dgm,
01200 brackt,stmin,stmax);
01201
01202
01203
01204 fx = fxm + stx*dgtest;
01205 fy = fym + sty*dgtest;
01206 dgx = dgxm + dgtest;
01207 dgy = dgym + dgtest;
01208
01209 }
01210
01211 else
01212 {
01213
01214
01215
01216
01217
01218 infoc = MoreThuente::cstep(stx,fx,dgx,sty,fy,dgy,stp,f,dg,
01219 brackt,stmin,stmax);
01220
01221 }
01222
01223
01224
01225
01226 if (brackt)
01227 {
01228 if (fabs(sty - stx) >= 0.66 * width1)
01229 stp = stx + 0.5 * (sty - stx);
01230 width1 = width;
01231 width = fabs(sty-stx);
01232 }
01233
01234 }
01235
01236 }
01237
01238 template <typename PointSource>
01239 int NDTMatcherSequentialD2D<PointSource>::MoreThuente::cstep(double& stx, double& fx, double& dx,
01240 double& sty, double& fy, double& dy,
01241 double& stp, double& fp, double& dp,
01242 bool& brackt, double stmin, double stmax)
01243 {
01244 int info = 0;
01245
01246
01247
01248 if ((brackt && ((stp <= MoreThuente::min(stx, sty)) || (stp >= MoreThuente::max(stx, sty)))) ||
01249 (dx * (stp - stx) >= 0.0) || (stmax < stmin))
01250 return info;
01251
01252
01253
01254 double sgnd = dp * (dx / fabs(dx));
01255
01256
01257
01258
01259
01260
01261 bool bound;
01262 double theta;
01263 double s;
01264 double gamma;
01265 double p,q,r;
01266 double stpc, stpq, stpf;
01267
01268 if (fp > fx)
01269 {
01270 info = 1;
01271 bound = 1;
01272 theta = 3 * (fx - fp) / (stp - stx) + dx + dp;
01273
01274
01275
01276 s = MoreThuente::absmax(theta, dx, dp);
01277 gamma = s * sqrt(((theta / s) * (theta / s)) - (dx / s) * (dp / s));
01278 if (stp < stx)
01279 gamma = -gamma;
01280
01281 p = (gamma - dx) + theta;
01282 q = ((gamma - dx) + gamma) + dp;
01283 r = p / q;
01284 stpc = stx + r * (stp - stx);
01285 stpq = stx + ((dx / ((fx - fp) / (stp - stx) + dx)) / 2) * (stp - stx);
01286 if (fabs(stpc - stx) < fabs(stpq - stx))
01287 stpf = stpc;
01288 else
01289 stpf = stpc + (stpq - stpc) / 2;
01290
01291 brackt = true;
01292 }
01293
01294
01295
01296
01297
01298
01299 else if (sgnd < 0.0)
01300 {
01301 info = 2;
01302 bound = false;
01303 theta = 3 * (fx - fp) / (stp - stx) + dx + dp;
01304 s = MoreThuente::absmax(theta,dx,dp);
01305 gamma = s * sqrt(((theta/s) * (theta/s)) - (dx / s) * (dp / s));
01306 if (stp > stx)
01307 gamma = -gamma;
01308 p = (gamma - dp) + theta;
01309 q = ((gamma - dp) + gamma) + dx;
01310 r = p / q;
01311 stpc = stp + r * (stx - stp);
01312 stpq = stp + (dp / (dp - dx)) * (stx - stp);
01313 if (fabs(stpc - stp) > fabs(stpq - stp))
01314 stpf = stpc;
01315 else
01316 stpf = stpq;
01317 brackt = true;
01318 }
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329 else if (fabs(dp) < fabs(dx))
01330 {
01331 info = 3;
01332 bound = true;
01333 theta = 3 * (fx - fp) / (stp - stx) + dx + dp;
01334 s = MoreThuente::absmax(theta, dx, dp);
01335
01336
01337
01338
01339 gamma = s * sqrt(max(0,(theta / s) * (theta / s) - (dx / s) * (dp / s)));
01340 if (stp > stx)
01341 gamma = -gamma;
01342
01343 p = (gamma - dp) + theta;
01344 q = (gamma + (dx - dp)) + gamma;
01345 r = p / q;
01346 if ((r < 0.0) && (gamma != 0.0))
01347 stpc = stp + r * (stx - stp);
01348 else if (stp > stx)
01349 stpc = stmax;
01350 else
01351 stpc = stmin;
01352
01353 stpq = stp + (dp/ (dp - dx)) * (stx - stp);
01354 if (brackt)
01355 {
01356 if (fabs(stp - stpc) < fabs(stp - stpq))
01357 stpf = stpc;
01358 else
01359 stpf = stpq;
01360 }
01361 else
01362 {
01363 if (fabs(stp - stpc) > fabs(stp - stpq))
01364 stpf = stpc;
01365 else
01366 stpf = stpq;
01367 }
01368 }
01369
01370
01371
01372
01373
01374
01375 else
01376 {
01377 info = 4;
01378 bound = false;
01379 if (brackt)
01380 {
01381 theta = 3 * (fp - fy) / (sty - stp) + dy + dp;
01382 s = MoreThuente::absmax(theta, dy, dp);
01383 gamma = s * sqrt(((theta/s)*(theta/s)) - (dy / s) * (dp / s));
01384 if (stp > sty)
01385 gamma = -gamma;
01386 p = (gamma - dp) + theta;
01387 q = ((gamma - dp) + gamma) + dy;
01388 r = p / q;
01389 stpc = stp + r * (sty - stp);
01390 stpf = stpc;
01391 }
01392 else if (stp > stx)
01393 stpf = stmax;
01394 else
01395 stpf = stmin;
01396 }
01397
01398
01399
01400
01401 if (fp > fx)
01402 {
01403 sty = stp;
01404 fy = fp;
01405 dy = dp;
01406 }
01407 else
01408 {
01409 if (sgnd < 0.0)
01410 {
01411 sty = stx;
01412 fy = fx;
01413 dy = dx;
01414 }
01415 stx = stp;
01416 fx = fp;
01417 dx = dp;
01418 }
01419
01420
01421
01422 stpf = MoreThuente::min(stmax, stpf);
01423 stpf = MoreThuente::max(stmin, stpf);
01424 stp = stpf;
01425 if (brackt && bound)
01426 {
01427 if (sty > stx)
01428 stp = min(stx + 0.66 * (sty - stx), stp);
01429 else
01430 stp = max(stx + 0.66 * (sty - stx), stp);
01431 }
01432
01433 return info;
01434
01435 }
01436
01437 template <typename PointSource>
01438 double NDTMatcherSequentialD2D<PointSource>::MoreThuente::min(double a, double b)
01439 {
01440 return (a < b ? a : b);
01441 }
01442
01443 template <typename PointSource>
01444 double NDTMatcherSequentialD2D<PointSource>::MoreThuente::max(double a, double b)
01445 {
01446 return (a > b ? a : b);
01447 }
01448
01449 template <typename PointSource>
01450 double NDTMatcherSequentialD2D<PointSource>::MoreThuente::absmax(double a, double b, double c)
01451 {
01452 a = fabs(a);
01453 b = fabs(b);
01454 c = fabs(c);
01455
01456 if (a > b)
01457 return (a > c) ? a : c;
01458 else
01459 return (b > c) ? b : c;
01460 }
01461
01462 template <typename PointSource>
01463 double NDTMatcherSequentialD2D<PointSource>::normalizeAngle(double a)
01464 {
01465
01466 return atan2(sin(a), cos(a));
01467
01468 }
01469
01470
01471
01472 }