00001 #include <ndt_map/pointcloud_utils.h>
00002 #include <pcl/registration/transformation_estimation_svd.h>
00003 #include <ndt_map/ndt_histogram.h>
00004
00005 namespace lslgeneric{
00006
00007 NDTHistogram::NDTHistogram(){
00008 N_LINE_BINS = 1;
00009 N_FLAT_BINS = 40;
00010 N_SPHERE_BINS = 10;
00011
00012 histogramBinsLine = std::vector<int>(N_LINE_BINS,0);
00013 histogramBinsFlat = std::vector<int>(N_FLAT_BINS,0);
00014 histogramBinsSphere = std::vector<int>(N_SPHERE_BINS,0);
00015
00016 for(int i=0; i<3; i++)
00017 {
00018 dist_histogramBinsLine[i] = std::vector<int>(N_LINE_BINS,0);
00019 dist_histogramBinsFlat[i] = std::vector<int>(N_FLAT_BINS,0);
00020 dist_histogramBinsSphere[i] = std::vector<int>(N_SPHERE_BINS,0);
00021 }
00022
00023 D1 = 5;
00024 D2 = 10;
00025
00026 averageDirections = std::vector<Eigen::Vector3d,Eigen::aligned_allocator<Eigen::Vector3d> >(N_FLAT_BINS,Eigen::Vector3d(0,0,0));
00027 computeDirections();
00028
00029 topThree.reserve(3);
00030 for(int r=0; r<3; r++)
00031 {
00032 topThree[r].setIdentity();
00033 topThreeS[r] = INT_MAX;
00034 }
00035 inited = true;
00036 }
00037
00038 NDTHistogram::NDTHistogram (const NDTHistogram& other){
00039
00040 histogramBinsLine = other.histogramBinsLine;
00041 histogramBinsFlat = other.histogramBinsFlat;
00042 histogramBinsSphere = other.histogramBinsSphere;
00043
00044 for(int i=0; i<3; i++)
00045 {
00046 dist_histogramBinsLine[i] = other.dist_histogramBinsLine[i];
00047 dist_histogramBinsFlat[i] = other.dist_histogramBinsFlat[i];
00048 dist_histogramBinsSphere[i] = other.dist_histogramBinsSphere[i];
00049 }
00050
00051 D1 = 5;
00052 D2 = 10;
00053
00054 averageDirections = other.averageDirections;
00055 directions = other.directions;
00056
00057 topThree.reserve(3);
00058 for(int r=0; r<3; r++){
00059 topThree[r].setIdentity();
00060 topThreeS[r] = INT_MAX;
00061 }
00062 inited = true;
00063 }
00064
00065 NDTHistogram::NDTHistogram (NDTMap &map){
00066
00067 N_LINE_BINS = 1;
00068 N_FLAT_BINS = 40;
00069 N_SPHERE_BINS = 10;
00070
00071 histogramBinsLine = std::vector<int>(N_LINE_BINS,0);
00072 histogramBinsFlat = std::vector<int>(N_FLAT_BINS,0);
00073 histogramBinsSphere = std::vector<int>(N_SPHERE_BINS,0);
00074
00075 for(int i=0; i<3; i++){
00076 dist_histogramBinsLine[i] = std::vector<int>(N_LINE_BINS,0);
00077 dist_histogramBinsFlat[i] = std::vector<int>(N_FLAT_BINS,0);
00078 dist_histogramBinsSphere[i] = std::vector<int>(N_SPHERE_BINS,0);
00079 }
00080
00081 D1 = 5;
00082 D2 = 10;
00083
00084 averageDirections = std::vector<Eigen::Vector3d,Eigen::aligned_allocator<Eigen::Vector3d> >(N_FLAT_BINS,Eigen::Vector3d(0,0,0));
00085
00086 computeDirections();
00087 constructHistogram(map);
00088
00089 topThree.reserve(3);
00090 for(int r=0; r<3; r++){
00091 topThree[r].setIdentity();
00092 topThreeS[r] = INT_MAX;
00093 }
00094
00095 inited = true;
00096 }
00097
00098
00099 void NDTHistogram::computeDirections(){
00100
00101 double dlong = M_PI*(3-sqrt(5));
00102 double dz = 2.0/N_FLAT_BINS;
00103 double longitude = 0;
00104 double z = 1 - dz/2;
00105
00106 for (int k = 0; k<N_FLAT_BINS; k++){
00107 double r = sqrt(1-z*z);
00108 Eigen::Vector3d v;
00109 v<<cos(longitude)*r, sin(longitude)*r, z;
00110 directions.push_back(v);
00111 z = z - dz;
00112 longitude = longitude + dlong;
00113 }
00114 }
00115
00116
00117 void NDTHistogram::constructHistogram(NDTMap &map){
00118
00119 SpatialIndex *si = map.getMyIndex();
00120 if(si==NULL) return;
00121
00122 double LINEAR_FACTOR = 50;
00123 double FLAT_FACTOR = 50;
00124
00125 typename std::vector<NDTCell*>::iterator it = si->begin();
00126 while(it!=si->end())
00127 {
00128
00129
00130 if(*it == NULL){
00131 it++;
00132 continue;
00133 }
00134 if(!(*it)->hasGaussian_){
00135 it++;
00136 continue;
00137 }
00138 Eigen::Matrix3d evecs = (*it)->getEvecs();
00139 Eigen::Vector3d evals = (*it)->getEvals();
00140
00141 int idMin,idMax,idMid;
00142 double minEval = evals.minCoeff(&idMin);
00143 double maxEval = evals.maxCoeff(&idMax);
00144 double midEval = -1;
00145 idMid = -1;
00146 for(int j=0; j<3; j++){
00147 if(j!=idMin && j!=idMax){
00148 midEval = evals(j);
00149 idMid = j;
00150 }
00151 }
00152 double dist = (*it)->getMean().norm();
00153
00154
00155 if(maxEval > midEval*LINEAR_FACTOR){
00156 incrementLineBin(dist);
00157 it++;
00158 continue;
00159 }
00160
00161 if(midEval > minEval*FLAT_FACTOR){
00162 Eigen::Vector3d normal = evecs.col(idMin);
00163 Eigen::Vector3d mean = (*it)->getMean();
00164 if(normal.dot(mean) < 0){
00165
00166 normal = -normal;
00167 }
00168 incrementFlatBin(normal,dist);
00169 it++;
00170 continue;
00171 }
00172
00173
00174 incrementSphereBin(dist);
00175
00176 it++;
00177 }
00178
00179 for(int i=0; i<averageDirections.size(); i++)
00180 {
00181 averageDirections[i].normalize();
00182 }
00183
00184 }
00185
00186 void NDTHistogram::incrementLineBin(double d){
00187 histogramBinsLine[0] ++;
00188 if(d<D1) dist_histogramBinsLine[0][0] ++;
00189 else if(d>D2) dist_histogramBinsLine[2][0] ++;
00190 else dist_histogramBinsLine[1][0] ++;
00191 }
00192
00193 void NDTHistogram::incrementFlatBin(Eigen::Vector3d &normal, double d){
00194
00195 normal.normalize();
00196
00197 double mindist = INT_MAX;
00198 int idmin = -1;
00199 for(unsigned int i=0; i<directions.size(); i++)
00200 {
00201 double dist = (directions[i]-normal).norm();
00202 if(mindist > dist)
00203 {
00204 mindist = dist;
00205 idmin = i;
00206 }
00207 }
00208
00209 if(idmin >=0 && idmin < histogramBinsFlat.size())
00210 {
00211 histogramBinsFlat[idmin] ++;
00212 averageDirections[idmin] += normal;
00213 if(d<D1) dist_histogramBinsFlat[0][idmin] ++;
00214 else if(d>D2) dist_histogramBinsFlat[2][idmin] ++;
00215 else dist_histogramBinsFlat[1][idmin] ++;
00216 }
00217 }
00218
00219 void NDTHistogram::incrementSphereBin(double d){
00220 histogramBinsSphere[0] ++;
00221 if(d<D1){
00222 int id = floor(((double)d*N_SPHERE_BINS)/(double)D1);
00223 dist_histogramBinsSphere[0][id] ++;
00224 }
00225 else if(d>D2){
00226 dist_histogramBinsSphere[2][0] ++;
00227 }
00228 else{
00229 int id = floor(((double)(d-D1)*N_SPHERE_BINS)/(double)D2);
00230 dist_histogramBinsSphere[1][id] ++;
00231 }
00232 }
00233
00234
00235 pcl::PointCloud<pcl::PointXYZ> NDTHistogram::getDominantDirections(int nDirections){
00236
00237 pcl::PointCloud<pcl::PointXYZ> ret;
00238 std::vector<bool> dominated (directions.size(),false);
00239 double NORM_MIN = 0.2;
00240 int MIN_SUPPORT = 3;
00241
00242 for(int i=0; i<nDirections; i++){
00243
00244 pcl::PointXYZ current;
00245
00246 bool found = false;
00247 int maxBin, idMax;
00248 while (!found){
00249 maxBin = -1;
00250 idMax = -1;
00251 for(int j=0; j<histogramBinsFlat.size(); j++){
00252 if(histogramBinsFlat[j] > maxBin && !dominated[j]){
00253 maxBin = histogramBinsFlat[j];
00254 idMax = j;
00255 }
00256 }
00257
00258 found = !dominated[idMax];
00259
00260
00261
00262
00263
00264
00265
00266 dominated[idMax] = true;
00267 if(idMax-1 >=0) dominated[idMax-1] = true;
00268 if(idMax+1 <dominated.size()) dominated[idMax+1] = true;
00269 if(maxBin < MIN_SUPPORT) break;
00270 }
00271
00272 if(maxBin < MIN_SUPPORT) break;
00273
00274
00275
00276 current.x = averageDirections[idMax](0);
00277 current.y = averageDirections[idMax](1);
00278 current.z = averageDirections[idMax](2);
00279
00280
00281
00282 ret.points.push_back(current);
00283 }
00284 return ret;
00285 }
00286
00287 void NDTHistogram::bestFitToHistogram(NDTHistogram &target, Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> &T, bool bound_transform)
00288 {
00289
00290
00291 int N = 3;
00292
00293 pcl::PointCloud<pcl::PointXYZ> dominantBinsMine, dominantBinsTarget;
00294
00295
00296 dominantBinsMine = this->getDominantDirections(N);
00297
00298 dominantBinsTarget = target.getDominantDirections(N);
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313 for(int r=0; r<3; r++)
00314 {
00315 topThree[r].setIdentity();
00316 topThreeS[r] = INT_MAX;
00317 }
00318 pcl::PointCloud<pcl::PointXYZ> mineNew, mineNew2;
00319 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> localT, localT2;
00320
00321
00322
00323 for(int a1 = 0; a1<dominantBinsMine.points.size(); a1++){
00324
00325 for(int b1 = a1+1; b1<dominantBinsMine.points.size(); b1++){
00326
00327
00328
00329
00330 for(int a2 = 0; a2<dominantBinsTarget.points.size(); a2++)
00331 {
00332 for(int b2 = 0; b2<dominantBinsTarget.points.size(); b2++)
00333 {
00334 if(a2 == b2) continue;
00335
00336
00337 pcl::PointCloud<pcl::PointXYZ> useMine, useTarget;
00338 useMine.points.push_back(dominantBinsMine[a1]);
00339 useMine.points.push_back(dominantBinsMine[b1]);
00340
00341 useTarget.points.push_back(dominantBinsTarget[a2]);
00342 useTarget.points.push_back(dominantBinsTarget[b2]);
00343
00344
00345 closedFormSolution(useMine, useTarget, localT2);
00346 double good2 = this->getSimilarity(target,localT2);
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433 Eigen::Quaternion<double> id, errorQ;
00434 id.setIdentity();
00435 errorQ = localT2.rotation();
00436 double angle = fabsf(acos(id.dot(errorQ))/2);
00437 if(angle > M_PI/8 && bound_transform)
00438 {
00439
00440 continue;
00441 }
00442 if(good2 < topThreeS[2])
00443 {
00444
00445
00446 if(good2 < topThreeS[1])
00447 {
00448 if(good2 < topThreeS[0])
00449 {
00450 topThree[2] = topThree[1];
00451 topThree[1] = topThree[0];
00452 topThree[0] = localT2;
00453 topThreeS[2] = topThreeS[1];
00454 topThreeS[1] = topThreeS[0];
00455 topThreeS[0] = good2;
00456 }
00457 else
00458 {
00459 topThree[2] = topThree[1];
00460 topThree[1] = localT2;
00461 topThreeS[2] = topThreeS[1];
00462 topThreeS[1] = good2;
00463 }
00464 }
00465 else
00466 {
00467 topThree[2] = localT2;
00468 topThreeS[2] = good2;
00469 }
00470 }
00471
00472 }
00473 }
00474
00475 }
00476 }
00477
00478 T = topThree[0];
00479
00480 if(dominantBinsMine.points.size() < 2 || dominantBinsTarget.points.size() < 2)
00481 {
00482 T.setIdentity();
00483 }
00484
00485 }
00486
00487 void NDTHistogram::closedFormSolution(pcl::PointCloud<pcl::PointXYZ> &src, pcl::PointCloud<pcl::PointXYZ> &tgt, Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> &T){
00488 T.setIdentity ();
00489 Eigen::Matrix3d H;
00490 Eigen::MatrixXd P1, P2;
00491 unsigned int itr=0;
00492 size_t size = src.points.size();
00493
00494
00495 P1 = Eigen::MatrixXd(size,3);
00496 P2 = Eigen::MatrixXd(size,3);
00497
00498 for(itr=0; itr<size; itr++)
00499 {
00500 P1(itr,0) = src.points[itr].x;
00501 P1(itr,1) = src.points[itr].y;
00502 P1(itr,2) = src.points[itr].z;
00503 P2(itr,0) = tgt.points[itr].x;
00504 P2(itr,1) = tgt.points[itr].y;
00505 P2(itr,2) = tgt.points[itr].z;
00506 }
00507 H = P1.transpose()*P2;
00508
00509
00510 Eigen::JacobiSVD<Eigen::Matrix3d> svd (H, Eigen::ComputeFullU | Eigen::ComputeFullV);
00511 Eigen::Matrix3d u = svd.matrixU ();
00512 Eigen::Matrix3d v = svd.matrixV ();
00513
00514
00515 if (u.determinant () * v.determinant () < 0)
00516 {
00517 for (int x = 0; x < 3; ++x)
00518 v (x, 2) *= -1;
00519 }
00520
00521 Eigen::Matrix3d R = v * u.transpose ();
00522
00523 T = R;
00524
00525 }
00526
00527 void NDTHistogram::printHistogram(bool bMatlab){
00528 if(bMatlab){
00529
00530 std::cout<<"L=[ ";
00531 for(unsigned int i=0; i<histogramBinsLine.size(); i++){
00532 std::cout<<histogramBinsLine[i]<<" ";
00533 }
00534 std::cout<<"];\n";
00535 std::cout<<"F=[";
00536 for(unsigned int i=0; i<histogramBinsFlat.size(); i++)
00537 {
00538 std::cout<<histogramBinsFlat[i]<<" ";
00539 }
00540 std::cout<<"];\n";
00541 for(unsigned int q=0; q<3; q++)
00542 {
00543 std::cout<<"F"<<q<<" = [";
00544 for(unsigned int i=0; i<dist_histogramBinsFlat[q].size(); i++)
00545 {
00546 std::cout<<dist_histogramBinsFlat[q][i]<<" ";
00547 }
00548 std::cout<<"];\n";
00549 }
00550
00551 std::cout<<"];\nS=[";
00552 for(unsigned int i=0; i<histogramBinsSphere.size(); i++)
00553 {
00554 std::cout<<histogramBinsSphere[i]<<" ";
00555 }
00556 std::cout<<"];\n";
00557 for(unsigned int q=0; q<3; q++)
00558 {
00559 std::cout<<"S"<<q<<" = [";
00560 for(unsigned int i=0; i<dist_histogramBinsSphere[q].size(); i++)
00561 {
00562 std::cout<<dist_histogramBinsSphere[q][i]<<" ";
00563 }
00564 std::cout<<"];\n";
00565 }
00566
00567
00568
00569
00570
00571
00572 }
00573 else
00574 {
00575 std::cout<<"L: ";
00576 for(unsigned int i=0; i<histogramBinsLine.size(); i++)
00577 {
00578 std::cout<<histogramBinsLine[i]<<" ";
00579 }
00580
00581 std::cout<<"\nF: ";
00582 for(unsigned int i=0; i<histogramBinsFlat.size(); i++)
00583 {
00584 std::cout<<histogramBinsFlat[i]<<" ";
00585 }
00586
00587 std::cout<<"\nS: ";
00588 for(unsigned int i=0; i<histogramBinsSphere.size(); i++)
00589 {
00590 std::cout<<histogramBinsSphere[i]<<" ";
00591 }
00592 std::cout<<"\n";
00593 }
00594 }
00595
00596
00597 double NDTHistogram::getSimilarity(NDTHistogram &other)
00598 {
00599
00600 Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> T;
00601
00602 this->bestFitToHistogram(other,T,false);
00603
00604 return this->getSimilarity(other,T);
00605 }
00606
00607
00608 double NDTHistogram::getSimilarity(NDTHistogram &other, Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> &T){
00609 double score[3];
00610 double N_THIS[3], N_OTHER[3];
00611 for(unsigned int r = 0; r<3; r++){
00612 N_THIS[r] = 0;
00613 N_OTHER[r] = 0;
00614 score[r] = 0;
00615 for(int i=0; i<histogramBinsFlat.size(); i++)
00616 {
00617 N_THIS[r] += dist_histogramBinsFlat[r][i];
00618 N_OTHER[r] += other.dist_histogramBinsFlat[r][i];
00619 }
00620 for(int i=0; i<histogramBinsSphere.size(); i++)
00621 {
00622 N_THIS[r] += dist_histogramBinsSphere[r][i] ;
00623 N_OTHER[r] += other.dist_histogramBinsSphere[r][i] ;
00624 }
00625 N_THIS[r] += dist_histogramBinsLine[r][0];
00626 N_OTHER[r]+= other.dist_histogramBinsLine[r][0];
00627 N_THIS[r] = N_THIS[r]==0 ? INT_MAX : N_THIS[r];
00628 N_OTHER[r] = N_OTHER[r]==0 ? INT_MAX : N_OTHER[r];
00629 }
00630
00631 for(int q = 0; q<averageDirections.size(); q++)
00632 {
00633
00634 Eigen::Vector3d tr = T*averageDirections[q];
00635 if( this->histogramBinsFlat[q] == 0)
00636 {
00637 tr = directions[q];
00638 }
00639
00640
00641 tr.normalize();
00642 double mindist = INT_MAX;
00643 int idmin = -1;
00644 for(unsigned int i=0; i<directions.size(); i++)
00645 {
00646 double dist = (directions[i]-tr).norm();
00647 if(mindist > dist)
00648 {
00649 mindist = dist;
00650 idmin = i;
00651 }
00652 }
00653
00654 if(!(idmin >=0 && idmin < histogramBinsFlat.size()))
00655 {
00656 continue;
00657 }
00658
00659 for(unsigned int r = 0; r<3; r++)
00660 {
00661 score[r] += pow((double)this->dist_histogramBinsFlat[r][q]/N_THIS[r] - (double)other.dist_histogramBinsFlat[r][idmin]/N_OTHER[r],2);
00662 }
00663
00664 }
00665 for(unsigned int r = 0; r<3; r++)
00666 {
00667 for(int i=0; i<histogramBinsSphere.size(); i++)
00668 {
00669 score[r] += pow( (double)this->dist_histogramBinsSphere[r][i]/N_THIS[r] - (double)other.dist_histogramBinsSphere[r][i]/N_OTHER[r] ,2);
00670 }
00671
00672 score[r] += pow( (double)this->dist_histogramBinsLine[r][0]/N_THIS[r] - (double)other.dist_histogramBinsLine[r][0]/N_OTHER[r] ,2);
00673 double maxN, minN;
00674 maxN = (N_THIS[r] > N_OTHER[r]) ? N_THIS[r] : N_OTHER[r];
00675 minN = (N_THIS[r] < N_OTHER[r]) ? N_THIS[r] : N_OTHER[r];
00676 minN = (minN < 1) ? 1 : minN;
00677
00678 score[r] = maxN*sqrt(score[r])/minN;
00679 }
00680
00681
00682 return score[0]+score[1];
00683 }
00684
00685 }