evaluation_features.cpp
Go to the documentation of this file.
00001 
00063 #include <cstdlib>
00064 
00065 #include <cob_3d_mapping_common/label_defines.h>
00066 #include <cob_3d_evaluation_features/label_results.h>
00067 
00068 #include <boost/program_options.hpp>
00069 #include <fstream>
00070 #include <math.h>
00071 
00072 #include <pcl/io/pcd_io.h>
00073 #include <pcl/point_types.h>
00074 
00075 #include <pcl/filters/voxel_grid.h>
00076 #include <pcl/filters/passthrough.h>
00077 #include <pcl/kdtree/kdtree_flann.h>
00078 #include <pcl/surface/mls.h>
00079 #include <pcl/features/normal_3d.h>
00080 #include <pcl/features/principal_curvatures.h>
00081 #include <pcl/features/rsd.h>
00082 #include <pcl/features/fpfh.h>
00083 
00084 #include <pcl/visualization/pcl_visualizer.h>
00085 #include <pcl/visualization/point_cloud_handlers.h>
00086 
00087 #include <opencv2/ml/ml.hpp>
00088 #include <opencv2/highgui/highgui.hpp>
00089 
00090 using namespace std;
00091 using namespace pcl;
00092 
00093 typedef visualization::PointCloudColorHandlerRGBField<PointXYZRGB> ColorHdlRGB;
00094 
00095 // The following global variables hold the boost::program_option option:
00096 float pass_depth_;
00097 
00098 bool rsd_enable_;
00099 bool rsd_mls_enable_;
00100 bool rsd_vox_enable_;
00101 float rsd_vox_;
00102 float rsd_rn_;
00103 float rsd_rf_;
00104 
00105 float r_limit_;
00106 float r_low;
00107 float r_high;
00108 float r_r1;
00109 float r_r2;
00110 
00111 bool pc_enable_;
00112 bool pc_mls_enable_;
00113 bool pc_vox_enable_;
00114 float pc_vox_;
00115 float pc_rn_;
00116 float pc_rf_;
00117 
00118 float c_low;
00119 float c_high;
00120 float c_r1; // sphere / cyl
00121 float c_r2; // corner / edge
00122 
00123 bool fpfh_enable_;
00124 bool fpfh_mls_enable_;
00125 bool fpfh_vox_enable_;
00126 float fpfh_vox_;
00127 float fpfh_rn_;
00128 float fpfh_rf_;
00129 
00130 string file_in_;
00131 string fpfh_svm_model_;
00132 string camera_pos_;
00133 bool quiet_;
00134 
00135 string fl2label(const float & f, const size_t & precision=3)
00136 {
00137   if (f == 0)
00138     return string(precision, '0');
00139 
00140   stringstream ss;
00141   ss << f;
00142   string s = ss.str();
00143   s = s.substr(2,s.length());
00144   if (precision > s.length())
00145     s += string(precision - s.length(), '0');
00146   return (s);
00147 }
00148 
00149 void readOptions(int argc, char* argv[])
00150 {
00151   using namespace boost::program_options;
00152 
00153   string config_file;
00154   options_description cmd("Command line options");
00155   options_description cfg("Config file options");
00156 
00157   cmd.add_options()
00158     ("help", "produce help message")
00159     ("config,c", value<string>(&config_file)->default_value("config/accuracy_evaluator.cfg"),
00160      "name of a file for configuration.")
00161     ("in,i", value<string>(&file_in_), "labeled input pcd file")
00162     ("svm_model,s", value<string>(&fpfh_svm_model_), "set svm to use svm")
00163     ("camera,C", value<string>(&camera_pos_), "specify a file for initial camera position")
00164     ("quiet,Q", "disable visualization")
00165     ;
00166   cfg.add_options()
00167     ("pass.depth", value<float>(&pass_depth_), "set depth of passthrough filter")
00168 
00169     ("rsd.enabled", value<bool>(&rsd_enable_), "enable rsd estimation")
00170     ("rsd.enable_mls", value<bool>(&rsd_mls_enable_), "enable surface smoothing for rsd")
00171     ("rsd.enable_vox", value<bool>(&rsd_vox_enable_), "enable voxelgrid filtering for rsd")
00172     ("rsd.voxel_size", value<float>(&rsd_vox_), "set a voxelgrid size for rsd")
00173     ("rsd.limit_rmax", value<float>(&r_limit_), "set the radius limit for rsd feature values")
00174     ("rsd.rn", value<float>(&rsd_rn_), "set the normal estimation radius for rsd")
00175     ("rsd.rf", value<float>(&rsd_rf_), "feature estimation radius for rsd")
00176     ("rsd.r_low", value<float>(&r_low), "")
00177     ("rsd.r_high", value<float>(&r_high), "")
00178     ("rsd.r_r1", value<float>(&r_r1), "sphere / cylinder")
00179     ("rsd.r_r2", value<float>(&r_r2), "edge / corner")
00180 
00181     ("pc.enabled", value<bool>(&pc_enable_), "enable principal curvature estimation")
00182     ("pc.enable_mls", value<bool>(&pc_mls_enable_), "enable surface smoothing for pc")
00183     ("pc.enable_vox", value<bool>(&pc_vox_enable_), "enable voxelgrid filtering for pc")
00184     ("pc.voxel_size", value<float>(&pc_vox_), "set a voxelgrid size for pc")
00185     ("pc.rn", value<float>(&pc_rn_), "set the normal estimation radius for pc")
00186     ("pc.rf", value<float>(&pc_rf_), "feature estimation radius for pc")
00187     ("pc.c_low",  value<float>(&c_low), "")
00188     ("pc.c_high", value<float>(&c_high), "")
00189     ("pc.c_r1",   value<float>(&c_r1), "sphere / cylinder")
00190     ("pc.c_r2",   value<float>(&c_r2), "edge / corner")
00191 
00192     ("fpfh.enabled", value<bool>(&fpfh_enable_), "enable fpfh estimation")
00193     ("fpfh.enable_mls", value<bool>(&fpfh_mls_enable_), "enable surface smoothing for fpfh")
00194     ("fpfh.enable_vox", value<bool>(&fpfh_vox_enable_), "enable voxelgrid filtering for fpfh")
00195     ("fpfh.voxel_size", value<float>(&fpfh_vox_), "set a voxelgrid size for fpfh")
00196     ("fpfh.rn", value<float>(&fpfh_rn_), "set the normal estimation radius for fpfh")
00197     ("fpfh.rf", value<float>(&fpfh_rf_), "feature estimation radius for fpfh")
00198     ;
00199 
00200   positional_options_description p_opt;
00201   p_opt.add("in", 1);
00202   cmd.add(cfg);
00203 
00204   variables_map vm;
00205   store(command_line_parser(argc, argv)
00206         .options(cmd)
00207         .positional(p_opt).run(), vm);
00208   notify(vm);
00209 
00210   if (vm.count("help"))
00211   {
00212     cout << cmd << endl;
00213     exit(0);
00214   }
00215   if (vm.count("quiet")) quiet_ = true;
00216   else quiet_ = false;
00217 
00218   ifstream ifs(config_file.c_str());
00219   if (!ifs)
00220     cout << "cannot open config file: " << config_file << endl;
00221   else
00222   {
00223     store(parse_config_file(ifs, cmd), vm);
00224     notify(vm);
00225   }
00226 }
00227 
00236 void processFPFH(const PointCloud<PointXYZRGB>::Ptr in,
00237                  PointCloud<PointXYZRGB>::Ptr ref_out,
00238                  PointCloud<PointXYZRGB>::Ptr fpfh_out)
00239 {
00240   PointCloud<Normal>::Ptr n(new PointCloud<Normal>());
00241   PointCloud<FPFHSignature33>::Ptr fpfh(new PointCloud<FPFHSignature33>());
00242 
00243   // Passthrough filtering (needs to be done to remove NaNs)
00244   cout << "FPFH: Pass (with " << in->points.size() << " points)" << endl;
00245   PassThrough<PointXYZRGB> pass;
00246   pass.setInputCloud(in);
00247   pass.setFilterFieldName("z");
00248   pass.setFilterLimits(0.0f, pass_depth_);
00249   pass.filter(*ref_out);
00250 
00251   // Optional voxelgrid filtering
00252   if (fpfh_vox_enable_)
00253   {
00254     cout << "FPFH: Voxel (with " << ref_out->points.size() << " points)" << endl;
00255     VoxelGrid<PointXYZRGB> vox;
00256     vox.setInputCloud(ref_out);
00257     vox.setLeafSize(fpfh_vox_, fpfh_vox_, fpfh_vox_);
00258     vox.filter(*ref_out);
00259   }
00260 
00261   #ifdef PCL_VERSION_COMPARE //fuerte
00262     pcl::search::KdTree<PointXYZRGB>::Ptr tree (new pcl::search::KdTree<PointXYZRGB>());
00263   #else //electric
00264     pcl::KdTreeFLANN<PointXYZRGB>::Ptr tree (new pcl::KdTreeFLANN<PointXYZRGB> ());
00265   #endif
00266   //KdTree<PointXYZRGB>::Ptr tree(new KdTreeFLANN<PointXYZRGB>());
00267   tree->setInputCloud(ref_out);
00268 
00269   // Optional surface smoothing
00270   if(fpfh_mls_enable_)
00271   {
00272     cout << "FPFH: MLS (with " << ref_out->points.size() << " points)" << endl;
00273 
00274     #ifdef PCL_VERSION_COMPARE
00275       std::cerr << "MLS has changed completely in PCL 1.7! Requires redesign of entire program" << std::endl;
00276       exit(0);
00277     #else
00278       MovingLeastSquares<PointXYZRGB, Normal> mls;
00279       mls.setInputCloud(ref_out);
00280       mls.setOutputNormals(n);
00281       mls.setPolynomialFit(true);
00282       mls.setPolynomialOrder(2);
00283       mls.setSearchMethod(tree);
00284       mls.setSearchRadius(fpfh_rn_);
00285       mls.reconstruct(*ref_out);
00286     #endif
00287     cout << "FPFH: flip normals (with " << ref_out->points.size() << " points)" << endl;
00288     for (size_t i = 0; i < ref_out->points.size(); ++i)
00289     {
00290       flipNormalTowardsViewpoint(ref_out->points[i], 0.0f, 0.0f, 0.0f,
00291                                  n->points[i].normal[0],
00292                                  n->points[i].normal[1],
00293                                  n->points[i].normal[2]);
00294     }
00295   }
00296   else
00297   {
00298     cout << "FPFH: Normals (with " << ref_out->points.size() << " points)" << endl;
00299     NormalEstimation<PointXYZRGB, Normal> norm;
00300     norm.setInputCloud(ref_out);
00301     norm.setSearchMethod(tree);
00302     norm.setRadiusSearch(fpfh_rn_);
00303     norm.compute(*n);
00304   }
00305 
00306   // FPFH estimation
00307   #ifdef PCL_VERSION_COMPARE //fuerte
00308     tree.reset(new pcl::search::KdTree<PointXYZRGB>());
00309   #else //electric
00310     tree.reset(new KdTreeFLANN<PointXYZRGB> ());
00311   #endif
00312   tree->setInputCloud(ref_out);
00313   cout << "FPFH: estimation (with " << ref_out->points.size() << " points)" << endl;
00314   FPFHEstimation<PointXYZRGB, Normal, FPFHSignature33> fpfhE;
00315   fpfhE.setInputCloud(ref_out);
00316   fpfhE.setInputNormals(n);
00317   fpfhE.setSearchMethod(tree);
00318   fpfhE.setRadiusSearch(fpfh_rf_);
00319   fpfhE.compute(*fpfh);
00320 
00321   cout << "FPFH: classification " << endl;
00322   *fpfh_out = *ref_out;
00323 
00324   CvSVM svm;
00325   svm.load(fpfh_svm_model_.c_str());
00326   cv::Mat fpfh_histo(1, 33, CV_32FC1);
00327 
00328   int exp_rgb, pre_rgb, predict;
00329   cob_3d_mapping_common::LabelResults stats(fl2label(fpfh_rn_),fl2label(fpfh_rf_),fpfh_mls_enable_);
00330   for (size_t idx = 0; idx < ref_out->points.size(); idx++)
00331   {
00332     exp_rgb = *reinterpret_cast<int*>(&ref_out->points[idx].rgb); // expected label
00333     memcpy(fpfh_histo.ptr<float>(0), fpfh->points[idx].histogram, sizeof(fpfh->points[idx].histogram));
00334     predict = (int)svm.predict(fpfh_histo);
00335     //cout << predict << endl;
00336     switch(predict)
00337     {
00338     case SVM_PLANE:
00339       pre_rgb = LBL_PLANE;
00340       if (exp_rgb != LBL_PLANE && exp_rgb != LBL_UNDEF) stats.fp[EVAL_PLANE]++;
00341       break;
00342     case SVM_EDGE:
00343       pre_rgb = LBL_EDGE;
00344       if (exp_rgb != LBL_EDGE && exp_rgb != LBL_UNDEF) stats.fp[EVAL_EDGE]++;
00345       if (exp_rgb != LBL_COR && exp_rgb != LBL_EDGE && exp_rgb != LBL_UNDEF) stats.fp[EVAL_EDGECORNER]++;
00346       break;
00347     case SVM_COR:
00348       pre_rgb = LBL_COR;
00349       if (exp_rgb != LBL_COR && exp_rgb != LBL_UNDEF) stats.fp[EVAL_COR]++;
00350       if (exp_rgb != LBL_COR && exp_rgb != LBL_EDGE && exp_rgb != LBL_UNDEF) stats.fp[EVAL_EDGECORNER]++;
00351       break;
00352     case SVM_SPH:
00353       pre_rgb = LBL_SPH;
00354       if (exp_rgb != LBL_SPH && exp_rgb != LBL_UNDEF) stats.fp[EVAL_SPH]++;
00355       if (exp_rgb != LBL_SPH && exp_rgb != LBL_CYL && exp_rgb != LBL_UNDEF) stats.fp[EVAL_CURVED]++;
00356       break;
00357     case SVM_CYL:
00358       pre_rgb = LBL_CYL;
00359       if (exp_rgb != LBL_CYL && exp_rgb != LBL_UNDEF) stats.fp[EVAL_CYL]++;
00360       if (exp_rgb != LBL_SPH && exp_rgb != LBL_CYL && exp_rgb != LBL_UNDEF) stats.fp[EVAL_CURVED]++;
00361       break;
00362     default:
00363       pre_rgb = LBL_UNDEF;
00364       break;
00365     }
00366 
00367     switch(exp_rgb)
00368     {
00369     case LBL_PLANE:
00370       if (pre_rgb != exp_rgb) stats.fn[EVAL_PLANE]++;
00371       stats.exp[EVAL_PLANE]++;
00372       break;
00373     case LBL_EDGE:
00374       if (pre_rgb != exp_rgb)
00375       {
00376         stats.fn[EVAL_EDGE]++;
00377         if (pre_rgb != LBL_COR) stats.fn[EVAL_EDGECORNER]++;
00378       }
00379       stats.exp[EVAL_EDGE]++;
00380       stats.exp[EVAL_EDGECORNER]++;
00381       break;
00382     case LBL_COR:
00383       if (pre_rgb != exp_rgb)
00384       {
00385         stats.fn[EVAL_COR]++;
00386         if (pre_rgb != LBL_EDGE) stats.fn[EVAL_EDGECORNER]++;
00387       }
00388       stats.exp[EVAL_COR]++;
00389       stats.exp[EVAL_EDGECORNER]++;
00390       break;
00391     case LBL_SPH:
00392       if (pre_rgb != exp_rgb)
00393       {
00394         stats.fn[EVAL_SPH]++;
00395         if (pre_rgb != LBL_CYL) stats.fn[EVAL_CURVED]++;
00396       }
00397       stats.exp[EVAL_SPH]++;
00398       stats.exp[EVAL_CURVED]++;
00399       break;
00400     case LBL_CYL:
00401       if (pre_rgb != exp_rgb)
00402       {
00403         stats.fn[EVAL_CYL]++;
00404         if (pre_rgb != LBL_SPH) stats.fn[EVAL_CURVED]++;
00405       }
00406       stats.exp[EVAL_CYL]++;
00407       stats.exp[EVAL_CURVED]++;
00408       break;
00409     default:
00410       stats.undef++;
00411       break;
00412     }
00413     fpfh_out->points[idx].rgb = *reinterpret_cast<float*>(&pre_rgb);
00414   }
00415   cout << "FPFH:\n" << stats << endl << endl;
00416 }
00417 
00418 void processPC(const PointCloud<PointXYZRGB>::Ptr in,
00419                PointCloud<PointXYZRGB>::Ptr ref_out,
00420                PointCloud<PointXYZRGB>::Ptr pc_out)
00421 {
00422   PointCloud<Normal>::Ptr n(new PointCloud<Normal>());
00423   PointCloud<PrincipalCurvatures>::Ptr pc(new PointCloud<PrincipalCurvatures>());
00424 
00425   // passthrough filtering (needed to remove NaNs)
00426   cout << "PC: Pass (with " << in->points.size() << " points)" << endl;
00427   PassThrough<PointXYZRGB> pass;
00428   pass.setInputCloud(in);
00429   pass.setFilterFieldName("z");
00430   pass.setFilterLimits(0.0f, pass_depth_);
00431   pass.filter(*ref_out);
00432 
00433   // Optional voxelgrid filtering
00434   if (pc_vox_enable_)
00435   {
00436     cout << "PC: Voxel (with " << ref_out->points.size() << " points)" << endl;
00437     VoxelGrid<PointXYZRGB> vox;
00438     vox.setInputCloud(ref_out);
00439     vox.setLeafSize(pc_vox_, pc_vox_, pc_vox_);
00440     vox.filter(*ref_out);
00441   }
00442 
00443   #ifdef PCL_VERSION_COMPARE //fuerte
00444     pcl::search::KdTree<PointXYZRGB>::Ptr tree (new pcl::search::KdTree<PointXYZRGB>());
00445   #else //electric
00446     KdTreeFLANN<PointXYZRGB>::Ptr tree (new pcl::KdTreeFLANN<PointXYZRGB> ());
00447   #endif
00448   tree->setInputCloud(ref_out);
00449 
00450   // Optional surface smoothing
00451   if(pc_mls_enable_)
00452   {
00453     cout << "PC: MLS (with " << ref_out->points.size() << " points)" << endl;
00454 
00455     #ifdef PCL_VERSION_COMPARE
00456       std::cerr << "MLS has changed completely in PCL 1.7! Requires redesign of entire program" << std::endl;
00457       exit(0);
00458     #else
00459       MovingLeastSquares<PointXYZRGB, Normal> mls;
00460       mls.setInputCloud(ref_out);
00461       mls.setOutputNormals(n);
00462       mls.setPolynomialFit(true);
00463       mls.setPolynomialOrder(2);
00464       mls.setSearchMethod(tree);
00465       mls.setSearchRadius(pc_rn_);
00466       mls.reconstruct(*ref_out);
00467     #endif
00468     cout << "PC: flip normals (with " << ref_out->points.size() << " points)" << endl;
00469     for (size_t i = 0; i < ref_out->points.size(); ++i)
00470     {
00471       flipNormalTowardsViewpoint(ref_out->points[i], 0.0f, 0.0f, 0.0f,
00472                                  n->points[i].normal[0],
00473                                  n->points[i].normal[1],
00474                                  n->points[i].normal[2]);
00475     }
00476   }
00477   else
00478   {
00479     cout << "PC: Normals (with " << ref_out->points.size() << " points)" << endl;
00480     NormalEstimation<PointXYZRGB, Normal> norm;
00481     norm.setInputCloud(ref_out);
00482     norm.setSearchMethod(tree);
00483     norm.setRadiusSearch(pc_rn_);
00484     norm.compute(*n);
00485   }
00486 
00487   // estimate PC
00488   #ifdef PCL_VERSION_COMPARE //fuerte
00489     tree.reset(new pcl::search::KdTree<PointXYZRGB>());
00490   #else //electric
00491     tree.reset(new KdTreeFLANN<PointXYZRGB> ());
00492   #endif
00493   tree->setInputCloud(ref_out);
00494   cout << "PC: estimation (with " << ref_out->points.size() << " points)" << endl;
00495   PrincipalCurvaturesEstimation<PointXYZRGB, Normal, PrincipalCurvatures> pcE;
00496   pcE.setInputCloud(ref_out);
00497   pcE.setInputNormals(n);
00498   pcE.setSearchMethod(tree);
00499   pcE.setRadiusSearch(pc_rf_);
00500   pcE.compute(*pc);
00501 
00502   cout << "PC: classification " << endl;
00503   *pc_out = *ref_out;
00504 
00505   int exp_rgb, pre_rgb;
00506   float c_max,c_min;
00507   cob_3d_mapping_common::LabelResults stats(fl2label(pc_rn_),fl2label(pc_rf_),pc_mls_enable_);
00508 
00509   // apply rules to PC results
00510   for (size_t idx = 0; idx < ref_out->points.size(); idx++)
00511   {
00512     exp_rgb = *reinterpret_cast<int*>(&ref_out->points[idx].rgb); // expected label
00513     c_max = pc->points[idx].pc1;
00514     c_min = pc->points[idx].pc2;
00515 
00516     if ( c_max < c_low )
00517     {
00518       pre_rgb = LBL_PLANE;
00519       if (exp_rgb != LBL_PLANE && exp_rgb != LBL_UNDEF) stats.fp[EVAL_PLANE]++;
00520     }
00521     else if (c_max > c_high)
00522     {
00523       if (c_max < c_r2 * c_min)
00524       {
00525         pre_rgb = LBL_COR;
00526         if (exp_rgb != LBL_COR && exp_rgb != LBL_UNDEF) stats.fp[EVAL_COR]++;
00527       }
00528       else
00529       {
00530         pre_rgb = LBL_EDGE;
00531         if (exp_rgb != LBL_EDGE && exp_rgb != LBL_UNDEF) stats.fp[EVAL_EDGE]++;
00532       }
00533       // special case:  combined class for corner and edge
00534       if (exp_rgb != LBL_COR && exp_rgb != LBL_EDGE && exp_rgb != LBL_UNDEF)
00535         stats.fp[EVAL_EDGECORNER]++;
00536     }
00537     else
00538     {
00539       if (c_max < c_r1 * c_min)
00540       {
00541         pre_rgb = LBL_SPH;
00542         if (exp_rgb != LBL_SPH && exp_rgb != LBL_UNDEF) stats.fp[EVAL_SPH]++;
00543       }
00544       else
00545       {
00546         pre_rgb = LBL_CYL;
00547         if (exp_rgb != LBL_CYL && exp_rgb != LBL_UNDEF) stats.fp[EVAL_CYL]++;
00548       }
00549       // special case:  combined class for sphere and cylinder
00550       if (exp_rgb != LBL_SPH && exp_rgb != LBL_CYL && exp_rgb != LBL_UNDEF)
00551         stats.fp[EVAL_CURVED]++;
00552     }
00553 
00554     switch(exp_rgb)
00555     {
00556     case LBL_PLANE:
00557       if (pre_rgb != exp_rgb) stats.fn[EVAL_PLANE]++;
00558       stats.exp[EVAL_PLANE]++;
00559       break;
00560     case LBL_EDGE:
00561       if (pre_rgb != exp_rgb)
00562       {
00563         stats.fn[EVAL_EDGE]++;
00564         if (pre_rgb != LBL_COR) stats.fn[EVAL_EDGECORNER]++;
00565       }
00566       stats.exp[EVAL_EDGE]++;
00567       stats.exp[EVAL_EDGECORNER]++;
00568       break;
00569     case LBL_COR:
00570       if (pre_rgb != exp_rgb)
00571       {
00572         stats.fn[EVAL_COR]++;
00573         if (pre_rgb != LBL_EDGE) stats.fn[EVAL_EDGECORNER]++;
00574       }
00575       stats.exp[EVAL_COR]++;
00576       stats.exp[EVAL_EDGECORNER]++;
00577       break;
00578     case LBL_SPH:
00579       if (pre_rgb != exp_rgb)
00580       {
00581         stats.fn[EVAL_SPH]++;
00582         if (pre_rgb != LBL_CYL) stats.fn[EVAL_CURVED]++;
00583       }
00584       stats.exp[EVAL_SPH]++;
00585       stats.exp[EVAL_CURVED]++;
00586       break;
00587     case LBL_CYL:
00588       if (pre_rgb != exp_rgb)
00589       {
00590         stats.fn[EVAL_CYL]++;
00591         if (pre_rgb != LBL_SPH) stats.fn[EVAL_CURVED]++;
00592       }
00593       stats.exp[EVAL_CYL]++;
00594       stats.exp[EVAL_CURVED]++;
00595       break;
00596     default:
00597       stats.undef++;
00598       break;
00599     }
00600     pc_out->points[idx].rgb = *reinterpret_cast<float*>(&pre_rgb);
00601   }
00602   cout << "PC:\n" << stats << endl << endl;
00603 }
00604 
00605 void processRSD(const PointCloud<PointXYZRGB>::Ptr in,
00606                 PointCloud<PointXYZRGB>::Ptr ref_out,
00607                 PointCloud<PointXYZRGB>::Ptr rsd_out)
00608 {
00609   PointCloud<Normal>::Ptr n(new PointCloud<Normal>());
00610   PointCloud<PrincipalRadiiRSD>::Ptr rsd(new PointCloud<PrincipalRadiiRSD>());
00611 
00612   // passthrough filtering (needed to remove NaNs)
00613   cout << "RSD: Pass (with " << in->points.size() << " points)" << endl;
00614   PassThrough<PointXYZRGB> pass;
00615   pass.setInputCloud(in);
00616   pass.setFilterFieldName("z");
00617   pass.setFilterLimits(0.0f, pass_depth_);
00618   pass.filter(*ref_out);
00619 
00620   // optional voxelgrid filtering
00621   if (rsd_vox_enable_)
00622   {
00623     cout << "RSD: Voxel (with " << ref_out->points.size() << " points)" << endl;
00624     VoxelGrid<PointXYZRGB> vox;
00625     vox.setInputCloud(ref_out);
00626     vox.setLeafSize(rsd_vox_, rsd_vox_, rsd_vox_);
00627     vox.filter(*ref_out);
00628   }
00629 
00630   #ifdef PCL_VERSION_COMPARE //fuerte
00631     pcl::search::KdTree<PointXYZRGB>::Ptr tree (new pcl::search::KdTree<PointXYZRGB>());
00632   #else //electric
00633     KdTreeFLANN<PointXYZRGB>::Ptr tree (new pcl::KdTreeFLANN<PointXYZRGB> ());
00634   #endif
00635   tree->setInputCloud(ref_out);
00636 
00637   // optional surface smoothing
00638   if(rsd_mls_enable_)
00639   {
00640     cout << "RSD: MLS (with " << ref_out->points.size() << " points)" << endl;
00641 
00642     #ifdef PCL_VERSION_COMPARE
00643       std::cerr << "MLS has changed completely in PCL 1.7! Requires redesign of entire program" << std::endl;
00644       exit(0);
00645     #else
00646       MovingLeastSquares<PointXYZRGB, Normal> mls;
00647       mls.setInputCloud(ref_out);
00648       mls.setOutputNormals(n);
00649       mls.setPolynomialFit(true);
00650       mls.setPolynomialOrder(2);
00651       mls.setSearchMethod(tree);
00652       mls.setSearchRadius(rsd_rn_);
00653       mls.reconstruct(*ref_out);
00654     #endif
00655 
00656     cout << "RSD: flip normals (with " << ref_out->points.size() << " points)" << endl;
00657     for (size_t i = 0; i < ref_out->points.size(); ++i)
00658     {
00659       flipNormalTowardsViewpoint(ref_out->points[i], 0.0f, 0.0f, 0.0f,
00660                                  n->points[i].normal[0],
00661                                  n->points[i].normal[1],
00662                                  n->points[i].normal[2]);
00663     }
00664   }
00665   else
00666   {
00667     cout << "RSD: Normals (with " << ref_out->points.size() << " points)" << endl;
00668     NormalEstimation<PointXYZRGB, Normal> norm;
00669     norm.setInputCloud(ref_out);
00670     norm.setSearchMethod(tree);
00671     norm.setRadiusSearch(rsd_rn_);
00672     norm.compute(*n);
00673   }
00674 
00675   tree->setInputCloud(ref_out);
00676 
00677   // RSD estimation
00678   cout << "RSD: estimation (with " << ref_out->points.size() << " points)" << endl;
00679   RSDEstimation<PointXYZRGB, Normal, PrincipalRadiiRSD> rsdE;
00680   rsdE.setInputCloud(ref_out);
00681   rsdE.setInputNormals(n);
00682   rsdE.setSearchMethod(tree);
00683   rsdE.setPlaneRadius(r_limit_);
00684   rsdE.setRadiusSearch(rsd_rf_);
00685   rsdE.compute(*rsd);
00686 
00687   cout << "RSD: classification " << endl;
00688   *rsd_out = *ref_out;
00689 
00690   // apply RSD rules for classification
00691   int exp_rgb, pre_rgb;
00692   float r_max,r_min;
00693   cob_3d_mapping_common::LabelResults stats(fl2label(rsd_rn_),fl2label(rsd_rf_),rsd_mls_enable_);
00694   for (size_t idx = 0; idx < ref_out->points.size(); idx++)
00695   {
00696     exp_rgb = *reinterpret_cast<int*>(&ref_out->points[idx].rgb); // expected label
00697     r_max = rsd->points[idx].r_max;
00698     r_min = rsd->points[idx].r_min;
00699 
00700     if ( r_min > r_high )
00701     {
00702       pre_rgb = LBL_PLANE;
00703       if (exp_rgb != LBL_PLANE && exp_rgb != LBL_UNDEF) stats.fp[EVAL_PLANE]++;
00704     }
00705     else if (r_min < r_low)
00706     {
00707       if (r_max < r_r2 * r_min)
00708       {
00709         pre_rgb = LBL_COR;
00710         if (exp_rgb != LBL_COR && exp_rgb != LBL_UNDEF) stats.fp[EVAL_COR]++;
00711       }
00712       else
00713       {
00714         pre_rgb = LBL_EDGE;
00715         if (exp_rgb != LBL_EDGE && exp_rgb != LBL_UNDEF) stats.fp[EVAL_EDGE]++;
00716       }
00717       // special case:  combined class for corner and edge
00718       if (exp_rgb != LBL_COR && exp_rgb != LBL_EDGE && exp_rgb != LBL_UNDEF)
00719         stats.fp[EVAL_EDGECORNER]++;
00720     }
00721     else
00722     {
00723       if (r_max < r_r1 * r_min)
00724       {
00725         pre_rgb = LBL_SPH;
00726         if (exp_rgb != LBL_SPH && exp_rgb != LBL_UNDEF) stats.fp[EVAL_SPH]++;
00727       }
00728       else
00729       {
00730         pre_rgb = LBL_CYL;
00731         if (exp_rgb != LBL_CYL && exp_rgb != LBL_UNDEF) stats.fp[EVAL_CYL]++;
00732       }
00733       // special case:  combined class for sphere and cylinder
00734       if (exp_rgb != LBL_SPH && exp_rgb != LBL_CYL && exp_rgb != LBL_UNDEF)
00735         stats.fp[EVAL_CURVED]++;
00736     }
00737 
00738     switch(exp_rgb)
00739     {
00740     case LBL_PLANE:
00741       if (pre_rgb != exp_rgb) stats.fn[EVAL_PLANE]++;
00742       stats.exp[EVAL_PLANE]++;
00743       break;
00744     case LBL_EDGE:
00745       if (pre_rgb != exp_rgb)
00746       {
00747         stats.fn[EVAL_EDGE]++;
00748         if (pre_rgb != LBL_COR) stats.fn[EVAL_EDGECORNER]++;
00749       }
00750       stats.exp[EVAL_EDGE]++;
00751       stats.exp[EVAL_EDGECORNER]++;
00752       break;
00753     case LBL_COR:
00754       if (pre_rgb != exp_rgb)
00755       {
00756         stats.fn[EVAL_COR]++;
00757         if (pre_rgb != LBL_EDGE) stats.fn[EVAL_EDGECORNER]++;
00758       }
00759       stats.exp[EVAL_COR]++;
00760       stats.exp[EVAL_EDGECORNER]++;
00761       break;
00762     case LBL_SPH:
00763       if (pre_rgb != exp_rgb)
00764       {
00765         stats.fn[EVAL_SPH]++;
00766         if (pre_rgb != LBL_CYL) stats.fn[EVAL_CURVED]++;
00767       }
00768       stats.exp[EVAL_SPH]++;
00769       stats.exp[EVAL_CURVED]++;
00770       break;
00771     case LBL_CYL:
00772       if (pre_rgb != exp_rgb)
00773       {
00774         stats.fn[EVAL_CYL]++;
00775         if (pre_rgb != LBL_SPH) stats.fn[EVAL_CURVED]++;
00776       }
00777       stats.exp[EVAL_CYL]++;
00778       stats.exp[EVAL_CURVED]++;
00779       break;
00780     default:
00781       stats.undef++;
00782       break;
00783     }
00784     rsd_out->points[idx].rgb = *reinterpret_cast<float*>(&pre_rgb);
00785   }
00786   cout << "RSD:\n" << stats << endl << endl;
00787 }
00788 
00789 
00790 int main(int argc, char** argv)
00791 {
00792   readOptions(argc, argv);
00793 
00794   PointCloud<PointXYZRGB>::Ptr p_raw(new PointCloud<PointXYZRGB>());
00795   PointCloud<PointXYZRGB>::Ptr p_rsd_out(new PointCloud<PointXYZRGB>());
00796   PointCloud<PointXYZRGB>::Ptr p_rsd_ref(new PointCloud<PointXYZRGB>());
00797   PointCloud<PointXYZRGB>::Ptr p_pc_out(new PointCloud<PointXYZRGB>());
00798   PointCloud<PointXYZRGB>::Ptr p_pc_ref(new PointCloud<PointXYZRGB>());
00799   PointCloud<PointXYZRGB>::Ptr p_fpfh_out(new PointCloud<PointXYZRGB>());
00800   PointCloud<PointXYZRGB>::Ptr p_fpfh_ref(new PointCloud<PointXYZRGB>());
00801 
00802   PCDReader r;
00803   if(r.read(file_in_, *p_raw) == -1)
00804     cout << "Could not read file " << file_in_ << endl;
00805   cout << "Read pcd file \"" << file_in_ << "\" (Points: " << p_raw->points.size() << ", width: "
00806        << p_raw->width << ", height: " << p_raw->height << ")" << endl;
00807 
00808   cout << "Headline: \n\n"<< cob_3d_mapping_common::writeHeader() << endl << endl;
00809 
00810   if (rsd_enable_)
00811     processRSD(p_raw, p_rsd_ref, p_rsd_out);
00812   if (pc_enable_)
00813     processPC(p_raw, p_pc_ref, p_pc_out);
00814   if (fpfh_enable_)
00815     processFPFH(p_raw, p_fpfh_ref, p_fpfh_out);
00816 
00817   if (quiet_) return (0);
00818 
00819   boost::shared_ptr<visualization::PCLVisualizer> v;
00820   if (camera_pos_ != "")
00821   {
00822     int argc_dummy = 3;
00823     char *argv_dummy[] = {(char*)argv[0], "-cam", (char*)camera_pos_.c_str(), NULL};
00824     v.reset(new visualization::PCLVisualizer(argc_dummy, argv_dummy, file_in_));
00825   }
00826   else
00827   {
00828     v.reset(new visualization::PCLVisualizer(file_in_));
00829   }
00830 
00831 
00832 
00833   /* --- Viewports: ---
00834    *  1y
00835    *    | 1 | 3 |
00836    * .5 ----+----
00837    *    | 2 | 4 |
00838    *  0    .5    1x
00839    * 1:
00840    */
00841   int v1(0);
00842   ColorHdlRGB col_hdl1(p_rsd_ref);
00843   v->createViewPort(0.0, 0.5, 0.5, 1.0, v1);
00844   v->setBackgroundColor(255,255,255, v1);
00845   v->addPointCloud<PointXYZRGB>(p_rsd_ref, col_hdl1, "raw", v1);
00846 
00847   // 2:
00848   int v2(0);
00849   ColorHdlRGB col_hdl2(p_fpfh_out);
00850   v->createViewPort(0.0, 0.0, 0.5, 0.5, v2);
00851   v->setBackgroundColor(255,255,255, v2);
00852   v->addPointCloud<PointXYZRGB>(p_fpfh_out, col_hdl2, "fpfh", v2);
00853 
00854   // 3:
00855   int v3(0);
00856   ColorHdlRGB col_hdl3(p_rsd_out);
00857   v->createViewPort(0.5, 0.5, 1.0, 1.0, v3);
00858   v->setBackgroundColor(255,255,255, v3);
00859   v->addPointCloud<PointXYZRGB>(p_rsd_out, col_hdl3, "rsd", v3);
00860 
00861   // 4:
00862   int v4(0);
00863   ColorHdlRGB col_hdl4(p_pc_out);
00864   v->createViewPort(0.5, 0.0, 1.0, 0.5, v4);
00865   v->setBackgroundColor(255,255,255, v4);
00866   v->addPointCloud<PointXYZRGB>(p_pc_out, col_hdl4, "pc", v4);
00867 
00868 
00869   while(!v->wasStopped())
00870   {
00871     v->spinOnce(100);
00872     usleep(100000);
00873   }
00874   return(0);
00875 }


cob_3d_evaluation_features
Author(s): Georg Arbeiter
autogenerated on Wed Aug 26 2015 11:04:38