00001 #include "Eigen/Eigen"
00002 #include "ndt_map/ndt_cell.h"
00003 #include <fstream>
00004 #include <vector>
00005 #include <ndt_map/lazy_grid.h>
00006 #include <ndt_registration/ndt_matcher_p2d.h>
00007
00008 namespace lslgeneric
00009 {
00010
00011
00012
00013 void NDTMatcherP2D::init(bool useDefaultGridResolutions, std::vector<double> _resolutions)
00014 {
00015
00017 double lfc1,lfc2,lfd3;
00018 double integral, outlier_ratio, support_size;
00019 integral = 0.1;
00020 outlier_ratio = 0.01;
00021
00022 support_size = 4;
00023 lfc1 = (1-outlier_ratio)/integral;
00024 lfc2 = outlier_ratio/pow(support_size,3);
00025 lfd3 = -log(lfc2);
00026 lfd1 = -log( lfc1 + lfc2 ) - lfd3;
00027 lfd2 = -log((-log( lfc1 * exp( -0.5 ) + lfc2 ) - lfd3 ) / lfd1);
00028
00029
00030
00032 useSimpleDerivatives = false;
00033 Jest.setZero();
00034 Jest.block<3,3>(0,0).setIdentity();
00035 Hest.setZero();
00036 NUMBER_OF_ACTIVE_CELLS = 0;
00037 ITR_MAX = 100;
00038 subsample_size = 0.4;
00039
00040 if(useDefaultGridResolutions)
00041 {
00042 resolutions.push_back(0.2);
00043 resolutions.push_back(0.5);
00044 resolutions.push_back(1);
00045 resolutions.push_back(2);
00046 }
00047 else
00048 {
00049 resolutions = _resolutions;
00050 }
00051 Eigen::Vector3d tt;
00052 tt.setZero();
00053 precomputeAngleDerivatives(tt);
00054 }
00055
00056 void NDTMatcherP2D::generateScoreDebug(const char* out, pcl::PointCloud<pcl::PointXYZ>& fixed,
00057 pcl::PointCloud<pcl::PointXYZ>& moving)
00058 {
00059
00060 std::ofstream lg(out,std::ios_base::out);
00061 int N_LINEAR = 100;
00062 int N_ROT = 100;
00063
00064 std::cout<<"generating scores...\n";
00065 for(int q = resolutions.size()-1; q>=0; q--)
00066 {
00067 current_resolution = resolutions[q];
00068 std::cout<<"res "<<current_resolution<<std::endl;
00069 double lfc1,lfc2,lfd3;
00070 double integral, outlier_ratio, support_size;
00071 integral = 0.1;
00072 outlier_ratio = 0.35;
00073 support_size = current_resolution;
00074 lfc1 = (1-outlier_ratio)/integral;
00075 lfc2 = outlier_ratio/pow(support_size,3);
00076 lfd3 = -log(lfc2);
00077 lfd1 = -(-log( lfc1 + lfc2 ) - lfd3);
00078 lfd2 = -log((-log( lfc1 * exp( -0.5 ) + lfc2 ) - lfd3 ) / -lfd1);
00079
00080 double lmin=-2, lmax=2, rmin=-M_PI/2, rmax=M_PI/2;
00081 double lstep = (lmax-lmin)/(N_LINEAR-1);
00082 double rstep = (rmax-rmin)/(N_ROT-1);
00083 Eigen::MatrixXd S(6,N_LINEAR);
00084 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> T;
00085
00086 LazyGrid prototype(current_resolution);
00087 NDTMap ndt( &prototype );
00088 ndt.loadPointCloud( fixed );
00089 ndt.computeNDTCells();
00090
00091 int k=0;
00092 for(double x=lmin; x<lmax; x+=lstep)
00093 {
00094 T = Eigen::Translation<double,3>(x,0,0);
00095
00096 pcl::PointCloud<pcl::PointXYZ> cloud = moving;
00097 lslgeneric::transformPointCloudInPlace(T,cloud);
00098
00099 S(0,k) = scorePointCloud(cloud,ndt);
00100 k++;
00101 }
00102 k=0;
00103 for(double x=lmin; x<lmax; x+=lstep)
00104 {
00105 T = Eigen::Translation<double,3>(0,x,0);
00106
00107 pcl::PointCloud<pcl::PointXYZ> cloud = moving;
00108 lslgeneric::transformPointCloudInPlace(T,cloud);
00109
00110 S(1,k) = scorePointCloud(cloud,ndt);
00111 k++;
00112 }
00113 k=0;
00114 for(double x=lmin; x<lmax; x+=lstep)
00115 {
00116 T = Eigen::Translation<double,3>(0.,0.,x);
00117
00118 pcl::PointCloud<pcl::PointXYZ> cloud = moving;
00119 lslgeneric::transformPointCloudInPlace(T,cloud);
00120
00121 S(2,k) = scorePointCloud(cloud,ndt);
00122 k++;
00123 }
00124
00125 k=0;
00126 for(double r=rmin; r<rmax; r+=rstep)
00127 {
00128 T = Eigen::AngleAxis<double>(r,Eigen::Vector3d::UnitX()) *
00129 Eigen::AngleAxis<double>(0,Eigen::Vector3d::UnitY()) *
00130 Eigen::AngleAxis<double>(0,Eigen::Vector3d::UnitZ()) ;
00131 pcl::PointCloud<pcl::PointXYZ> cloud = moving;
00132 lslgeneric::transformPointCloudInPlace(T,cloud);
00133 S(3,k) = scorePointCloud(cloud,ndt);
00134 k++;
00135 }
00136 k=0;
00137 for(double r=rmin; r<rmax; r+=rstep)
00138 {
00139 T = Eigen::AngleAxis<double>(0,Eigen::Vector3d::UnitX()) *
00140 Eigen::AngleAxis<double>(r,Eigen::Vector3d::UnitY()) *
00141 Eigen::AngleAxis<double>(0,Eigen::Vector3d::UnitZ()) ;
00142 pcl::PointCloud<pcl::PointXYZ> cloud = moving;
00143 lslgeneric::transformPointCloudInPlace(T,cloud);
00144
00145 S(4,k) = scorePointCloud(cloud,ndt);
00146 k++;
00147 }
00148 k=0;
00149 for(double r=rmin; r<rmax; r+=rstep)
00150 {
00151 T = Eigen::AngleAxis<double>(0,Eigen::Vector3d::UnitX()) *
00152 Eigen::AngleAxis<double>(0,Eigen::Vector3d::UnitY()) *
00153 Eigen::AngleAxis<double>(r,Eigen::Vector3d::UnitZ()) ;
00154 pcl::PointCloud<pcl::PointXYZ> cloud = moving;
00155 lslgeneric::transformPointCloudInPlace(T,cloud);
00156
00157 S(5,k) = scorePointCloud(cloud,ndt);
00158 k++;
00159 }
00160
00161 lg<<"Sp2f"<<(int)current_resolution<<" = ["<<S<<"];\n";
00162 }
00163 lg.close();
00164
00165 }
00166
00167 bool NDTMatcherP2D::match( pcl::PointCloud<pcl::PointXYZ>& target,
00168 pcl::PointCloud<pcl::PointXYZ>& source,
00169 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor>& T )
00170 {
00171
00172 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> Temp;
00173 T.setIdentity();
00174
00175 bool ret;
00176 pcl::PointCloud<pcl::PointXYZ> moving;
00177 if(subsample_size > 0) {
00178 moving = subsample(source);
00179 } else {
00180 moving = source;
00181 }
00182
00183
00184 for(int i=resolutions.size()-1; i>=0; i--) {
00185 current_resolution = resolutions[i];
00186
00187
00188
00189 LazyGrid prototype(current_resolution);
00190 NDTMap ndt( &prototype );
00191 ndt.loadPointCloud( target );
00192 ndt.computeNDTCells();
00193
00194 ret = this->match( ndt, moving, Temp );
00195 T = Temp*T;
00196
00197 lslgeneric::transformPointCloudInPlace(Temp,moving);
00198 #ifdef DO_DEBUG_PROC
00199 Eigen::Vector3d out = Temp.rotation().eulerAngles(0,1,2);
00200 std::cout<<"OUT: "<<out.transpose()<<std::endl;
00201 std::cout<<"translation "<<Temp.translation().transpose()<<std::endl;
00202
00203 #endif
00204 }
00205
00206 return ret;
00207 }
00208
00209 bool NDTMatcherP2D::covariance( pcl::PointCloud<pcl::PointXYZ>& target,
00210 pcl::PointCloud<pcl::PointXYZ>& source,
00211 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor>& T,
00212 Eigen::Matrix<double,6,6> &cov
00213 )
00214 {
00215
00216 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> TR;
00217 pcl::PointCloud<pcl::PointXYZ> cloud = source;
00218 lslgeneric::transformPointCloudInPlace(T,cloud);
00219
00220 LazyGrid prototype(current_resolution);
00221 NDTMap ndt( &prototype );
00222 ndt.loadPointCloud( target );
00223 ndt.computeNDTCells();
00224
00225 TR.setIdentity();
00226 Eigen::Matrix<double,6,1> sc;
00227 derivativesPointCloud(cloud,ndt,TR,sc,cov,true);
00228
00229
00230
00231 Eigen::FullPivLU<Eigen::Matrix<double,6,6> > dec(cov);
00232 Eigen::Matrix<double,6,6> invH;
00233 if (dec.isInvertible())
00234 {
00235 std::cout << "nice, we have invertible Hessian\n" << cov << "\n";
00236 }
00237 else
00238 {
00239 std::cerr << "Hessian is not invertible:\n" << cov << "\n";
00240 return false;
00241 }
00242 invH = dec.inverse();
00243 cov = 0.5*invH;
00244
00245
00246
00247 return true;
00248 }
00249
00250 bool NDTMatcherP2D::match( NDTMap& targetNDT,
00251 pcl::PointCloud<pcl::PointXYZ>& source,
00252 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor>& T )
00253 {
00255 double lfc1,lfc2,lfd3;
00256 double integral, outlier_ratio, support_size;
00257 integral = 0.1;
00258 outlier_ratio = 0.35;
00259
00260 support_size = current_resolution;
00261 lfc1 = (1-outlier_ratio)/integral;
00262 lfc2 = outlier_ratio/pow(support_size,3);
00263 lfd3 = -log(lfc2);
00264 lfd1 = -log( lfc1 + lfc2 ) - lfd3;
00265 lfd2 = -log((-log( lfc1 * exp( -0.5 ) + lfc2 ) - lfd3 ) / lfd1);
00266
00267
00268
00270 useSimpleDerivatives = true;
00271 Jest.setZero();
00272 Jest.block<3,3>(0,0).setIdentity();
00273 Hest.setZero();
00274
00275
00276
00277 bool convergence = false;
00278 double score=0;
00279 double DELTA_SCORE = 0.0001;
00280
00281 double NORM_MAX = 4*support_size, ROT_MAX = M_PI/4;
00282 int itr_ctr = 0;
00283 double step_size = 1;
00284 Eigen::Matrix<double,6,1> pose_increment_v, pose_increment_reg_v, score_gradient, scg;
00285 Eigen::Matrix<double,6,6> Hessian;
00286 Eigen::Matrix3d cov;
00287 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> TR, Tbest;
00288 Eigen::Vector3d transformed_vec, mean;
00289 bool ret = true;
00290
00291 pcl::PointCloud<pcl::PointXYZ> prevCloud, nextCloud;
00292 prevCloud = source;
00293 nextCloud = source;
00294 T.setIdentity();
00295 TR.setIdentity();
00296 Eigen::Vector3d eulerAngles = T.rotation().eulerAngles(0,1,2);
00297
00298 double scoreP = 0;
00299 double score_best = INT_MAX;
00300
00301 while(!convergence)
00302 {
00303
00304 score_gradient.setZero();
00305 Hessian.setZero();
00306
00307
00308 TR.setIdentity();
00309 derivativesPointCloud(prevCloud,targetNDT,TR,score_gradient,Hessian,true);
00310 scg = score_gradient;
00311
00312 Eigen::SelfAdjointEigenSolver<Eigen::Matrix<double,6,6> > Sol (Hessian);
00313 Eigen::Matrix<double,6,1> evals = Sol.eigenvalues().real();
00314 double minCoeff = evals.minCoeff();
00315 double maxCoeff = evals.maxCoeff();
00316 if(minCoeff < 0)
00317 {
00318
00319 Eigen::Matrix<double,6,6> evecs = Sol.eigenvectors().real();
00320 double regularizer = score_gradient.norm();
00321 regularizer = regularizer + minCoeff > 0 ? regularizer : 0.001*maxCoeff - minCoeff;
00322
00323 Eigen::Matrix<double,6,1> reg;
00324
00325 reg<<regularizer,regularizer,regularizer,regularizer,regularizer,regularizer;
00326 evals += reg;
00327 Eigen::Matrix<double,6,6> Lam;
00328 Lam = evals.asDiagonal();
00329 Hessian = evecs*Lam*(evecs.transpose());
00330 }
00331
00332 pose_increment_v = Hessian.ldlt().solve(-score_gradient);
00333
00334 score = scorePointCloud(prevCloud,targetNDT);
00335 if(score < score_best)
00336 {
00337 Tbest = T;
00338 score_best = score;
00339 }
00340
00341
00342
00343
00344 #if 0
00345 double pnorm = sqrt(pose_increment_v(0)*pose_increment_v(0) + pose_increment_v(1)*pose_increment_v(1)
00346 +pose_increment_v(2)*pose_increment_v(2));
00347 if(pnorm > NORM_MAX)
00348 {
00349 pose_increment_v(0) = NORM_MAX*pose_increment_v(0)/pnorm;
00350 pose_increment_v(1) = NORM_MAX*pose_increment_v(1)/pnorm;
00351 pose_increment_v(2) = NORM_MAX*pose_increment_v(2)/pnorm;
00352 }
00353 pose_increment_v(3) = normalizeAngle(pose_increment_v(3));
00354 pose_increment_v(3) = (pose_increment_v(3) > ROT_MAX) ? ROT_MAX : pose_increment_v(3);
00355 pose_increment_v(3) = (pose_increment_v(3) < -ROT_MAX) ? -ROT_MAX : pose_increment_v(3);
00356 pose_increment_v(4) = normalizeAngle(pose_increment_v(4));
00357 pose_increment_v(4) = (pose_increment_v(4) > ROT_MAX) ? ROT_MAX : pose_increment_v(4);
00358 pose_increment_v(4) = (pose_increment_v(4) < -ROT_MAX) ? -ROT_MAX : pose_increment_v(4);
00359 pose_increment_v(5) = normalizeAngle(pose_increment_v(5));
00360 pose_increment_v(5) = (pose_increment_v(5) > ROT_MAX) ? ROT_MAX : pose_increment_v(5);
00361 pose_increment_v(5) = (pose_increment_v(5) < -ROT_MAX) ? -ROT_MAX : pose_increment_v(5);
00362
00363
00364
00365 #endif
00366 TR.setIdentity();
00367 TR = Eigen::Translation<double,3>(pose_increment_v(0),pose_increment_v(1),pose_increment_v(2))*
00368 Eigen::AngleAxis<double>(pose_increment_v(3),Eigen::Vector3d::UnitX()) *
00369 Eigen::AngleAxis<double>(pose_increment_v(4),Eigen::Vector3d::UnitY()) *
00370 Eigen::AngleAxis<double>(pose_increment_v(5),Eigen::Vector3d::UnitZ()) ;
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 step_size = lineSearchMT(score_gradient,pose_increment_v,prevCloud,TR,targetNDT);
00384 if(step_size < 0)
00385 {
00386
00387 return true;
00388 }
00389 pose_increment_v = step_size*pose_increment_v;
00390
00391
00392
00393 TR.setIdentity();
00394 TR = Eigen::Translation<double,3>(pose_increment_v(0),pose_increment_v(1),pose_increment_v(2))*
00395 Eigen::AngleAxis<double>(pose_increment_v(3),Eigen::Vector3d::UnitX()) *
00396 Eigen::AngleAxis<double>(pose_increment_v(4),Eigen::Vector3d::UnitY()) *
00397 Eigen::AngleAxis<double>(pose_increment_v(5),Eigen::Vector3d::UnitZ()) ;
00398 T = TR*T;
00399
00400
00401
00402
00403 prevCloud = lslgeneric::transformPointCloud<pcl::PointXYZ>(T,source);
00404 scoreP = score;
00405 score = scorePointCloud(prevCloud,targetNDT);
00406 if(score < score_best)
00407 {
00408 Tbest = T;
00409 score_best = score;
00410 }
00411
00412
00413
00414
00415 if(itr_ctr>0)
00416 {
00417 convergence = ((pose_increment_v.norm()) < DELTA_SCORE);
00418 }
00419 if(itr_ctr>ITR_MAX)
00420 {
00421 convergence = true;
00422 ret = false;
00423 }
00424 itr_ctr++;
00425 }
00426
00427
00428
00429
00430 T = Tbest;
00431 this->finalscore = score/NUMBER_OF_ACTIVE_CELLS;
00432 return ret;
00433 }
00434
00435
00436 void NDTMatcherP2D::check( pcl::PointCloud<pcl::PointXYZ>& fixed,
00437 pcl::PointCloud<pcl::PointXYZ>& moving,
00438 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor>& T )
00439 {
00440
00441
00442
00443
00444
00445
00446
00447 }
00448
00449
00450
00451 bool NDTMatcherP2D::update_score_gradient(Eigen::Matrix<double,6,1> &score_gradient,
00452 Eigen::Vector3d &transformed,
00453 Eigen::Matrix3d & Cinv)
00454 {
00455
00456 Eigen::Vector3d CxX, CxdX;
00457 double factor = (-lfd2*transformed.dot(Cinv*transformed)/2);
00458
00459
00460 if(factor < -120)
00461 {
00462 return false;
00463 }
00464 factor = lfd2*exp(factor);
00465 if(factor > 1 || factor < 0 || factor*0 !=0)
00466 {
00467 return false;
00468 }
00469 factor *=lfd1;
00470
00471 for(int i=0; i<6; i++)
00472 {
00473 CxdX = Cinv*Jest.col(i);
00474 score_gradient(i) += transformed.dot(CxdX)*factor;
00475 }
00476 return true;
00477
00478 }
00479
00480 void NDTMatcherP2D::update_hessian(Eigen::Matrix<double,6,6> &Hessian,
00481 Eigen::Vector3d &transformed,
00482 Eigen::Matrix3d & Cinv)
00483 {
00484
00485 Eigen::Vector3d CxX, CxdXdI, CxdXdJ, CxSecondOrder;
00486 CxX = Cinv*transformed;
00487 double factor = lfd1*lfd2*exp(-lfd2*transformed.dot(CxX)/2);
00488 for(int i=0; i<Hessian.rows(); i++)
00489 {
00490 for(int j=0; j<Hessian.cols(); j++)
00491 {
00492
00493 CxdXdI = Cinv*Jest.col(i);
00494 CxdXdJ = Cinv*Jest.col(j);
00495 CxSecondOrder = Cinv*Hest.block<3,1>(3*i,j);
00496
00497 Hessian(i,j) += factor*(-lfd2*transformed.dot(CxdXdI)*transformed.dot(CxdXdJ) +
00498 transformed.dot(CxSecondOrder) +
00499 Jest.col(j).dot(CxdXdI) );
00500 }
00501 }
00502
00503 }
00504
00505 void NDTMatcherP2D::precomputeAngleDerivatives(Eigen::Vector3d &eulerAngles)
00506 {
00507 if(fabsf(eulerAngles(0)) < 10e-5) eulerAngles(0) = 0;
00508 if(fabsf(eulerAngles(1)) < 10e-5) eulerAngles(1) = 0;
00509 if(fabsf(eulerAngles(2)) < 10e-5) eulerAngles(2) = 0;
00510 double cx,cy,cz, sx,sy,sz;
00511 cx = cos(eulerAngles(0));
00512 cy = cos(eulerAngles(1));
00513 cz = cos(eulerAngles(2));
00514 sx = sin(eulerAngles(0));
00515 sy = sin(eulerAngles(1));
00516 sz = sin(eulerAngles(2));
00517
00518 jest13 << (-sx*sz+cx*sy*cz) , (-sx*cz - cx*sy*sz) , (-cx*cy) ;
00519 jest23 << (cx*sz+sx*sy*cz) , (cx*cz-sx*sy*sz) , (-sx*cy);
00520 jest04 << (-sy*cz) , sy*sz , cy;
00521 jest14 << sx*cy*cz , (-sx*cy*sz) , sx*sy;
00522 jest24 << (-cx*cy*cz) , cx*cy*sz , (-cx*sy);
00523 jest05 << (-cy*sz) , (-cy*cz), 0;
00524 jest15 << (cx*cz-sx*sy*sz) , (-cx*sz - sx*sy*cz), 0;
00525 jest25 << (sx*cz + cx*sy*sz) ,(cx*sy*cz - sx*sz), 0;
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536 a2 << (-cx*sz-sx*sy*cz),(-cx*cz+sx*sy*sz),sx*cy;
00537 a3 << (-sx*sz+cx*sy*cz),(-cx*sy*sz-sx*cz),(-cx*cy);
00538 b2 << (cx*cy*cz),(-cx*cy*sz),(cx*sy);
00539 b3 << (sx*cy*cz),(-sx*cy*sz),(sx*sy);
00540 c2 << (-sx*cz-cx*sy*sz),(sx*sz-cx*sy*cz),0;
00541 c3 << (cx*cz-sx*sy*sz),(-sx*sy*cz-cx*sz),0;
00542 d1 << (-cy*cz),(cy*sz),(sy);
00543 d2 << (-sx*sy*cz),(sx*sy*sz),(sx*cy);
00544 d3 << (cx*sy*cz),(-cx*sy*sz),(-cx*cy);
00545 e1 << (sy*sz),(sy*cz),0;
00546 e2 << (-sx*cy*sz),(-sx*cy*cz),0;
00547 e3 << (cx*cy*sz),(cx*cy*cz),0;
00548 f1 << (-cy*cz),(cy*sz),0;
00549 f2 << (-cx*sz -sx*sy*cz),(-cx*cz+sx*sy*sz),0;
00550 f3 << (-sx*sz+cx*sy*cz),(-cx*sy*sz-sx*cz),0;
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568 }
00569 void NDTMatcherP2D::computeDerivatives(pcl::PointXYZ &pt)
00570 {
00571
00572 if(useSimpleDerivatives)
00573 {
00574 Jest(1,3) = -pt.z;
00575 Jest(2,3) = pt.y;
00576 Jest(0,4) = pt.z;
00577 Jest(2,4) = -pt.x;
00578 Jest(0,5) = -pt.y;
00579 Jest(1,5) = pt.x;
00580
00581
00582 Hest(10,3) = -pt.y;
00583 Hest(11,3) = -pt.z;
00584
00585 Hest(13,3) = pt.x;
00586
00587 Hest(17,3) = pt.x;
00588
00589 Hest(10,4) = pt.x;
00590
00591 Hest(12,4) = -pt.x;
00592 Hest(14,4) = -pt.z;
00593
00594 Hest(17,4) = pt.y;
00595
00596 Hest(11,5) = pt.x;
00597
00598 Hest(14,5) = pt.y;
00599
00600 Hest(15,5) = -pt.x;
00601 Hest(16,5) = -pt.y;
00602 return;
00603 }
00604
00605 Eigen::Vector3d x;
00606 x<<pt.x,pt.y,pt.z;
00607
00608
00609 Jest(1,3) = x.dot(jest13);
00610 Jest(2,3) = x.dot(jest23);
00611 Jest(0,4) = x.dot(jest04);
00612 Jest(1,4) = x.dot(jest14);
00613 Jest(2,4) = x.dot(jest24);
00614 Jest(0,5) = x.dot(jest05);
00615 Jest(1,5) = x.dot(jest15);
00616 Jest(2,5) = x.dot(jest25);
00617
00618 Eigen::Vector3d a,b,c,d,e,f;
00619
00620 a<<0,x.dot(a2),x.dot(a3);
00621 b<<0,x.dot(b2),x.dot(b3);
00622 c<<0,x.dot(c2),x.dot(c3);
00623 d<<x.dot(d1),x.dot(d2),x.dot(d3);
00624 e<<x.dot(e1),x.dot(e2),x.dot(e3);
00625 f<<x.dot(f1),x.dot(f2),x.dot(f3);
00626
00627
00628 Hest.block<3,1>(9,3) = a;
00629 Hest.block<3,1>(12,3) = b;
00630 Hest.block<3,1>(15,3) = c;
00631 Hest.block<3,1>(9,4) = b;
00632 Hest.block<3,1>(12,4) = d;
00633 Hest.block<3,1>(15,4) = e;
00634 Hest.block<3,1>(9,5) = c;
00635 Hest.block<3,1>(12,5) = e;
00636 Hest.block<3,1>(15,5) = f;
00637
00638 }
00639
00640 double NDTMatcherP2D::scorePointCloud(pcl::PointCloud<pcl::PointXYZ> &source,
00641 NDTMap &targetNDT)
00642 {
00643 double score_here = 0;
00644 double score_native = 0;
00645 NDTCell *cell;
00646 Eigen::Matrix3d icov;
00647 Eigen::Vector3d mean;
00648 Eigen::Vector3d point;
00649 NUMBER_OF_ACTIVE_CELLS = 0;
00650 for(unsigned int i=0; i<source.points.size(); i++)
00651 {
00652 point<<source.points[i].x,source.points[i].y,source.points[i].z;
00653
00654 std::vector<NDTCell*> cells = targetNDT.getCellsForPoint(source.points[i],current_resolution);
00655 for(unsigned int j=0; j<cells.size(); j++)
00656 {
00657 cell = cells[j];
00658
00659
00660
00661
00662
00663 if(cell == NULL)
00664 {
00665 continue;
00666 }
00667 icov = cell->getInverseCov();
00668 mean = cell->getMean();
00669 double l = (point-mean).dot(icov*(point-mean));
00670 if(l*0 != 0) continue;
00671
00672 if(l > 120) continue;
00673
00674 score_here += (lfd1*exp(-lfd2*l/2));
00675 score_native += (targetNDT.getLikelihoodForPoint(source.points[i]));
00676 NUMBER_OF_ACTIVE_CELLS += 1;
00677 }
00678 }
00679
00680
00681 return score_here;
00682 }
00683
00684
00685 void NDTMatcherP2D::derivativesPointCloud(pcl::PointCloud<pcl::PointXYZ> &source,
00686 NDTMap &targetNDT,
00687 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> &transform,
00688
00689 Eigen::Matrix<double,6,1> &score_gradient,
00690 Eigen::Matrix<double,6,6> &Hessian,
00691 bool computeHessian)
00692 {
00693
00694 NDTCell *cell;
00695 Eigen::Vector3d transformed;
00696 Eigen::Matrix3d Cinv;
00697
00698
00699 Jest.setZero();
00700 Jest.block<3,3>(0,0).setIdentity();
00701 Hest.setZero();
00702
00703 score_gradient.setZero();
00704 Hessian.setZero();
00705
00706
00707
00708 for(unsigned int i=0; i<source.points.size(); i++)
00709 {
00710 transformed<<source.points[i].x,source.points[i].y,source.points[i].z;
00711
00712
00713
00714
00715
00716
00717 {
00718 if(!targetNDT.getCellForPoint(source.points[i],cell))
00719 {
00720 continue;
00721 }
00722
00723 if(cell == NULL)
00724 {
00725 continue;
00726 }
00727 transformed -=cell->getMean();
00728 Cinv = cell->getInverseCov();
00729
00730
00731 computeDerivatives(source.points[i]);
00732
00733
00734 if(!update_score_gradient(score_gradient, transformed, Cinv))
00735 {
00736 continue;
00737 }
00738
00739
00740 if(computeHessian)
00741 {
00742 update_hessian(Hessian, transformed, Cinv);
00743 }
00744 cell = NULL;
00745 }
00746 }
00747 score_gradient = -score_gradient * (1.0 / source.points.size());
00748 Hessian = -Hessian * (1.0 / source.points.size());
00749 }
00750
00751
00752 double NDTMatcherP2D::lineSearchMT( Eigen::Matrix<double,6,1> &score_gradient_init,
00753 Eigen::Matrix<double,6,1> &increment,
00754 pcl::PointCloud<pcl::PointXYZ> &sourceCloud,
00755 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> &globalT,
00756 NDTMap &targetNDT)
00757 {
00758
00759
00760 double stp = 4.0;
00761 double recoverystep = 0.05;
00762 double dginit = 0.0;
00763 double ftol = 0.0001;
00764 double gtol = 0.9999;
00765 double stpmax = 10.0;
00766 double stpmin = 0.0001;
00767 int maxfev = 10;
00768 double xtol = 0.01;
00769
00770 double direction = 1.0;
00771
00772 pcl::PointCloud<pcl::PointXYZ> cloudHere = sourceCloud;
00773
00774 double score_init = 0.0;
00775
00776 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> ps,ps2;
00777 Eigen::Matrix<double,6,1> pincr, score_gradient_here;
00778 Eigen::Matrix<double,6,6> pseudoH;
00779 Eigen::Vector3d eulerAngles;
00781
00782 int info = 0;
00783 int infoc = 1;
00784
00785
00786
00787
00788
00789 score_init = scorePointCloud(cloudHere,targetNDT);
00790
00791
00792
00793
00794
00795
00796
00797
00798 dginit = increment.dot(score_gradient_init);
00799
00800
00801 if (dginit >= 0.0)
00802 {
00803
00804
00805
00806 increment = -increment;
00807 dginit = -dginit;
00808 direction = -1;
00809
00810 if (dginit >= 0.0)
00811 {
00812
00813
00814
00815 return recoverystep;
00816 }
00817 }
00818 else
00819 {
00820
00821 }
00822
00823
00824
00825 bool brackt = false;
00826 bool stage1 = true;
00827 int nfev = 0;
00828 double dgtest = ftol * dginit;
00829 double width = stpmax - stpmin;
00830 double width1 = 2 * width;
00831
00832
00833
00834 double finit = 0.0;
00835 finit = score_init;
00836
00837
00838
00839
00840
00841
00842
00843
00844 double stx = 0.0;
00845 double fx = finit;
00846 double dgx = dginit;
00847 double sty = 0.0;
00848 double fy = finit;
00849 double dgy = dginit;
00850
00851
00852 double eta_original = -1.0;
00853 double eta = 0.0;
00854 eta = eta_original;
00855
00856
00857
00858 double stmin, stmax;
00859 double fm, fxm, fym, dgm, dgxm, dgym;
00860
00861 while (1)
00862 {
00863
00864
00865 if (brackt)
00866 {
00867 stmin = MoreThuente::min(stx, sty);
00868 stmax = MoreThuente::max(stx, sty);
00869 }
00870 else
00871 {
00872 stmin = stx;
00873 stmax = stp + 4 * (stp - stx);
00874 }
00875
00876
00877 stp = MoreThuente::max(stp, stpmin);
00878 stp = MoreThuente::min(stp, stpmax);
00879
00880
00881
00882
00883 if ((brackt && ((stp <= stmin) || (stp >= stmax))) ||
00884 (nfev >= maxfev - 1) || (infoc == 0) ||
00885 (brackt && (stmax - stmin <= xtol * stmax)))
00886 {
00887 stp = stx;
00888 }
00889
00890
00891
00893
00894 pincr = stp*increment;
00895
00896 ps = Eigen::Translation<double,3>(pincr(0),pincr(1),pincr(2))*
00897 Eigen::AngleAxisd(pincr(3),Eigen::Vector3d::UnitX())*
00898 Eigen::AngleAxisd(pincr(4),Eigen::Vector3d::UnitY())*
00899 Eigen::AngleAxisd(pincr(5),Eigen::Vector3d::UnitZ());
00900
00901
00902
00903
00904
00905 cloudHere = lslgeneric::transformPointCloud(ps,sourceCloud);
00906
00907 double f = 0.0;
00908 f = scorePointCloud(cloudHere,targetNDT);
00909 score_gradient_here.setZero();
00910
00911 ps2.setIdentity();
00912 derivativesPointCloud(cloudHere,targetNDT,ps2,score_gradient_here,pseudoH,false);
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926 double dg = 0.0;
00927 dg = increment.dot(score_gradient_here);
00928
00929
00930
00931
00932 nfev ++;
00933
00935
00936
00937
00938 double ftest1 = finit + stp * dgtest;
00939
00940
00941
00942
00943 if ((brackt && ((stp <= stmin) || (stp >= stmax))) || (infoc == 0))
00944 info = 6;
00945
00946 if ((stp == stpmax) && (f <= ftest1) && (dg <= dgtest))
00947 info = 5;
00948
00949 if ((stp == stpmin) && ((f > ftest1) || (dg >= dgtest)))
00950 info = 4;
00951
00952 if (nfev >= maxfev)
00953 info = 3;
00954
00955 if (brackt && (stmax-stmin <= xtol*stmax))
00956 info = 2;
00957
00958
00959 bool sufficientDecreaseTest = false;
00960 sufficientDecreaseTest = (f <= ftest1);
00961
00962
00963
00964
00965 if ((sufficientDecreaseTest) && (fabs(dg) <= gtol*(-dginit)))
00966 info = 1;
00967
00968 if (info != 0)
00969 {
00970 if (info != 1)
00971 {
00972
00973
00974
00975
00976 stp = recoverystep;
00977
00978
00979
00980
00981
00982 }
00983 else
00984 {
00985
00986 }
00987
00988
00989
00990
00991
00992 return stp;
00993
00994 }
00995
00996
00997
00998
00999
01000
01001
01002 if (stage1 && (f <= ftest1) && (dg >= MoreThuente::min(ftol, gtol) * dginit))
01003 {
01004 stage1 = false;
01005 }
01006
01007
01008
01009
01010
01011
01012
01013 if (stage1 && (f <= fx) && (f > ftest1))
01014 {
01015
01016
01017
01018 fm = f - stp * dgtest;
01019 fxm = fx - stx * dgtest;
01020 fym = fy - sty * dgtest;
01021 dgm = dg - dgtest;
01022 dgxm = dgx - dgtest;
01023 dgym = dgy - dgtest;
01024
01025
01026
01027
01028
01029 infoc = MoreThuente::cstep(stx,fxm,dgxm,sty,fym,dgym,stp,fm,dgm,
01030 brackt,stmin,stmax);
01031
01032
01033
01034 fx = fxm + stx*dgtest;
01035 fy = fym + sty*dgtest;
01036 dgx = dgxm + dgtest;
01037 dgy = dgym + dgtest;
01038
01039 }
01040
01041 else
01042 {
01043
01044
01045
01046
01047
01048 infoc = MoreThuente::cstep(stx,fx,dgx,sty,fy,dgy,stp,f,dg,
01049 brackt,stmin,stmax);
01050
01051 }
01052
01053
01054
01055
01056 if (brackt)
01057 {
01058 if (fabs(sty - stx) >= 0.66 * width1)
01059 stp = stx + 0.5 * (sty - stx);
01060 width1 = width;
01061 width = fabs(sty-stx);
01062 }
01063
01064 }
01065
01066 }
01067
01068
01069 int NDTMatcherP2D::MoreThuente::cstep(double& stx, double& fx, double& dx,
01070 double& sty, double& fy, double& dy,
01071 double& stp, double& fp, double& dp,
01072 bool& brackt, double stmin, double stmax)
01073 {
01074 int info = 0;
01075
01076
01077
01078 if ((brackt && ((stp <= MoreThuente::min(stx, sty)) || (stp >= MoreThuente::max(stx, sty)))) ||
01079 (dx * (stp - stx) >= 0.0) || (stmax < stmin))
01080 return info;
01081
01082
01083
01084 double sgnd = dp * (dx / fabs(dx));
01085
01086
01087
01088
01089
01090
01091 bool bound;
01092 double theta;
01093 double s;
01094 double gamma;
01095 double p,q,r;
01096 double stpc, stpq, stpf;
01097
01098 if (fp > fx)
01099 {
01100 info = 1;
01101 bound = 1;
01102 theta = 3 * (fx - fp) / (stp - stx) + dx + dp;
01103
01104
01105
01106 s = MoreThuente::absmax(theta, dx, dp);
01107 gamma = s * sqrt(((theta / s) * (theta / s)) - (dx / s) * (dp / s));
01108 if (stp < stx)
01109 gamma = -gamma;
01110
01111 p = (gamma - dx) + theta;
01112 q = ((gamma - dx) + gamma) + dp;
01113 r = p / q;
01114 stpc = stx + r * (stp - stx);
01115 stpq = stx + ((dx / ((fx - fp) / (stp - stx) + dx)) / 2) * (stp - stx);
01116 if (fabs(stpc - stx) < fabs(stpq - stx))
01117 stpf = stpc;
01118 else
01119 stpf = stpc + (stpq - stpc) / 2;
01120
01121 brackt = true;
01122 }
01123
01124
01125
01126
01127
01128
01129 else if (sgnd < 0.0)
01130 {
01131 info = 2;
01132 bound = false;
01133 theta = 3 * (fx - fp) / (stp - stx) + dx + dp;
01134 s = MoreThuente::absmax(theta,dx,dp);
01135 gamma = s * sqrt(((theta/s) * (theta/s)) - (dx / s) * (dp / s));
01136 if (stp > stx)
01137 gamma = -gamma;
01138 p = (gamma - dp) + theta;
01139 q = ((gamma - dp) + gamma) + dx;
01140 r = p / q;
01141 stpc = stp + r * (stx - stp);
01142 stpq = stp + (dp / (dp - dx)) * (stx - stp);
01143 if (fabs(stpc - stp) > fabs(stpq - stp))
01144 stpf = stpc;
01145 else
01146 stpf = stpq;
01147 brackt = true;
01148 }
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159 else if (fabs(dp) < fabs(dx))
01160 {
01161 info = 3;
01162 bound = true;
01163 theta = 3 * (fx - fp) / (stp - stx) + dx + dp;
01164 s = MoreThuente::absmax(theta, dx, dp);
01165
01166
01167
01168
01169 gamma = s * sqrt(max(0,(theta / s) * (theta / s) - (dx / s) * (dp / s)));
01170 if (stp > stx)
01171 gamma = -gamma;
01172
01173 p = (gamma - dp) + theta;
01174 q = (gamma + (dx - dp)) + gamma;
01175 r = p / q;
01176 if ((r < 0.0) && (gamma != 0.0))
01177 stpc = stp + r * (stx - stp);
01178 else if (stp > stx)
01179 stpc = stmax;
01180 else
01181 stpc = stmin;
01182
01183 stpq = stp + (dp/ (dp - dx)) * (stx - stp);
01184 if (brackt)
01185 {
01186 if (fabs(stp - stpc) < fabs(stp - stpq))
01187 stpf = stpc;
01188 else
01189 stpf = stpq;
01190 }
01191 else
01192 {
01193 if (fabs(stp - stpc) > fabs(stp - stpq))
01194 stpf = stpc;
01195 else
01196 stpf = stpq;
01197 }
01198 }
01199
01200
01201
01202
01203
01204
01205 else
01206 {
01207 info = 4;
01208 bound = false;
01209 if (brackt)
01210 {
01211 theta = 3 * (fp - fy) / (sty - stp) + dy + dp;
01212 s = MoreThuente::absmax(theta, dy, dp);
01213 gamma = s * sqrt(((theta/s)*(theta/s)) - (dy / s) * (dp / s));
01214 if (stp > sty)
01215 gamma = -gamma;
01216 p = (gamma - dp) + theta;
01217 q = ((gamma - dp) + gamma) + dy;
01218 r = p / q;
01219 stpc = stp + r * (sty - stp);
01220 stpf = stpc;
01221 }
01222 else if (stp > stx)
01223 stpf = stmax;
01224 else
01225 stpf = stmin;
01226 }
01227
01228
01229
01230
01231 if (fp > fx)
01232 {
01233 sty = stp;
01234 fy = fp;
01235 dy = dp;
01236 }
01237 else
01238 {
01239 if (sgnd < 0.0)
01240 {
01241 sty = stx;
01242 fy = fx;
01243 dy = dx;
01244 }
01245 stx = stp;
01246 fx = fp;
01247 dx = dp;
01248 }
01249
01250
01251
01252 stpf = MoreThuente::min(stmax, stpf);
01253 stpf = MoreThuente::max(stmin, stpf);
01254 stp = stpf;
01255 if (brackt && bound)
01256 {
01257 if (sty > stx)
01258 stp = min(stx + 0.66 * (sty - stx), stp);
01259 else
01260 stp = max(stx + 0.66 * (sty - stx), stp);
01261 }
01262
01263 return info;
01264
01265 }
01266
01267 double NDTMatcherP2D::MoreThuente::min(double a, double b)
01268 {
01269 return (a < b ? a : b);
01270 }
01271
01272 double NDTMatcherP2D::MoreThuente::max(double a, double b)
01273 {
01274 return (a > b ? a : b);
01275 }
01276
01277 double NDTMatcherP2D::MoreThuente::absmax(double a, double b, double c)
01278 {
01279 a = fabs(a);
01280 b = fabs(b);
01281 c = fabs(c);
01282
01283 if (a > b)
01284 return (a > c) ? a : c;
01285 else
01286 return (b > c) ? b : c;
01287 }
01288
01289 pcl::PointCloud<pcl::PointXYZ> NDTMatcherP2D::subsample(pcl::PointCloud<pcl::PointXYZ>& original)
01290 {
01291
01292 std::string subsampleType = "GRID";
01293 if(subsampleType == "NONE")
01294 {
01295 return original;
01296 }
01297 if(subsampleType == "GRID")
01298 {
01299 double subsampleRes = subsample_size;
01300 pcl::PointCloud<pcl::PointXYZ> res;
01301 LazyGrid prototype(subsampleRes);
01302 NDTMap ndt( &prototype );
01303 ndt.loadPointCloud( original );
01304 std::vector<NDTCell*>::iterator it = ndt.getMyIndex()->begin();
01305
01306 while(it!=ndt.getMyIndex()->end())
01307 {
01308 NDTCell* ndcell = (*it);
01309 if(ndcell!=NULL)
01310 {
01311 if(ndcell->points_.size() > 0)
01312 {
01313 res.points.push_back(ndcell->points_.front());
01314 }
01315 }
01316 it++;
01317 }
01318 return res;
01319
01320 }
01321
01322 #if 0
01323 if(subsampleType == "MEAN")
01324 {
01325 pcl::PointCloud<pcl::PointXYZ> res;
01326
01327 NDTMap ndt( new OctTree<PointSource>() );
01328 ndt.loadPointCloud( original );
01329 ndt.computeNDTCells();
01330 typename std::vector<Cell<PointSource>*>::iterator it = ndt.getMyIndex()->begin();
01331
01332 while(it!=ndt.getMyIndex()->end())
01333 {
01334 NDTCell<PointSource>* ndcell = dynamic_cast<NDTCell<PointSource>*>(*it);
01335 if(ndcell!=NULL)
01336 {
01337 if(ndcell->points_.size() > 0)
01338 {
01339 PointSource pt;
01340 Eigen::Vector3d m = ndcell->getMean();
01341 pt.x = m(0);
01342 pt.y = m(1);
01343 pt.z = m(2);
01344 res.points.push_back(pt);
01345 }
01346 }
01347 it++;
01348 }
01349 return res;
01350
01351 }
01352
01353 if(subsampleType == "TREE")
01354 {
01355
01356 pcl::PointCloud<PointSource> res;
01357
01358
01359
01360 NDTMap<PointSource> ndt( new OctTree<PointSource>() );
01361 ndt.loadPointCloud( original );
01362 ndt.computeNDTCells();
01363 typename std::vector<Cell<PointSource>*>::iterator it = ndt.getMyIndex()->begin();
01364
01365 while(it!=ndt.getMyIndex()->end())
01366 {
01367 NDTCell<PointSource>* ndcell = dynamic_cast<NDTCell<PointSource>*>(*it);
01368 if(ndcell!=NULL)
01369 {
01370 if(ndcell->points_.size() > 0)
01371 {
01372 res.points.push_back(ndcell->points_.front());
01373 }
01374 }
01375 it++;
01376 }
01377 return res;
01378 }
01379 #endif
01380
01381 return original;
01382 }
01383
01384 double NDTMatcherP2D::normalizeAngle(double a)
01385 {
01386
01387 return atan2(sin(a), cos(a));
01388
01389 }
01390
01391 }