PHVObjectClassifier.hpp
Go to the documentation of this file.
00001 /*
00002  * PHVObjectClassifier.hpp
00003  *
00004  *  Created on: Jun 9, 2012
00005  *      Author: vsu
00006  */
00007 
00008 #ifndef PHVOBJECTCLASSIFIER_HPP_
00009 #define PHVOBJECTCLASSIFIER_HPP_
00010 
00011 #include <pcl17/classification/PHVObjectClassifier.h>
00012 #include <opencv2/core/core.hpp>
00013 #include <pcl17/features/vfh.h>
00014 
00015 template<class FeatureT>
00016 cv::Mat transform_to_mat(const std::vector<FeatureT> & features) {
00017         int featureLength = sizeof(features[0].histogram) / sizeof(float);
00018 
00019         cv::Mat res(features.size(), featureLength, CV_32F);
00020         for (size_t i = 0; i < features.size(); i++) {
00021                 for (int j = 0; j < featureLength; j++) {
00022                         res.at<float>(i, j) = features[i].histogram[j];
00023                 }
00024         }
00025 
00026         return res;
00027 }
00028 
00029 template<class FeatureT>
00030 void transform_to_features(const cv::Mat & mat,
00031                 std::vector<FeatureT> & features) {
00032         features.clear();
00033         for (int i = 0; i < mat.rows; i++) {
00034                 FeatureT f;
00035                 for (int j = 0; j < mat.cols; j++) {
00036                         f.histogram[j] = mat.at<float>(i, j);
00037                 }
00038                 features.push_back(f);
00039         };
00040 }
00041 
00042 template<class PointT, class PointNormalT, class FeatureT>
00043 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::clusterFeatures(
00044                 vector<FeatureT> & cluster_centers, vector<int> & cluster_labels) {
00045         int featureLength = sizeof(features_[0].histogram) / sizeof(float);
00046 
00047         cv::Mat feature_vectors = transform_to_mat(features_);
00048         cv::Mat centers(num_clusters_, featureLength, feature_vectors.type()),
00049                         labels;
00050 
00051         cv::kmeans(feature_vectors, num_clusters_, labels,
00052                         cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0), 4,
00053                         cv::KMEANS_RANDOM_CENTERS, centers);
00054 
00055         transform_to_features(centers, cluster_centers);
00056         cluster_labels = labels;
00057 }
00058 
00059 template<class PointT, class PointNormalT, class FeatureT>
00060 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::saveToFile() {
00061 
00062         // Delete old and create new directory sturcture for output
00063         boost::filesystem::path output_path(database_dir_);
00064         boost::filesystem::path output_models_path(database_dir_ + "models/");
00065         if (boost::filesystem::exists(output_path)) {
00066                 boost::filesystem::remove_all(output_path);
00067         }
00068 
00069         boost::filesystem::create_directories(output_path);
00070         boost::filesystem::create_directories(output_models_path);
00071 
00072         YAML::Emitter out;
00073 
00074         out << *this;
00075 
00076         std::ofstream f;
00077         f.open((database_dir_ + "database.yaml").c_str());
00078         f << out.c_str();
00079         f.close();
00080 
00081 }
00082 
00083 template<class PointT, class PointNormalT, class FeatureT>
00084 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::loadFromFile() {
00085 
00086         std::ifstream fin((database_dir_ + "database.yaml").c_str());
00087         YAML::Parser parser(fin);
00088         YAML::Node doc;
00089         parser.GetNextDocument(doc);
00090 
00091         doc >> *this;
00092 
00093 }
00094 
00095 template<class PointT, class PointNormalT, class FeatureT>
00096 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::computeClassifier() {
00097 
00098         BOOST_FOREACH(ModelMapValueType &v, class_name_to_partial_views_map_) {
00099                 int view_num_counter = 0;
00100 
00101                 for (size_t i = 0; i < v.second.size(); i++) {
00102                         appendFeaturesFromCloud(v.second[i], v.first, view_num_counter);
00103                         view_num_counter++;
00104 
00105                 }
00106 
00107         }
00108 
00109         // Transform to model centroinds in local coordinate frame of the segment
00110         centroids_.getMatrixXfMap() *= -1;
00111 
00112         normalizeFeatures(features_);
00113 
00114         if (debug_) {
00115 
00116                 for (int i = 0; i < num_clusters_; i++) {
00117                         std::stringstream ss;
00118                         ss << debug_folder_ << "Cluster" << i << "/";
00119 
00120                         boost::filesystem::path output_path(ss.str());
00121                         if (boost::filesystem::exists(output_path)) {
00122                                 boost::filesystem::remove_all(output_path);
00123                         }
00124 
00125                         boost::filesystem::create_directories(output_path);
00126                 }
00127 
00128                 std::ofstream f((debug_folder_ + "features.txt").c_str());
00129 
00130                 size_t N = sizeof(features_[0].histogram) / sizeof(float);
00131 
00132                 for (size_t i = 0; i < features_.size(); i++) {
00133                         for (size_t j = 0; j < N; j++) {
00134                                 f << features_[i].histogram[j] << " ";
00135                         }
00136 
00137                         f << "\n";
00138 
00139                 }
00140 
00141                 f.close();
00142 
00143                 std::ofstream f2((debug_folder_ + "classnames.txt").c_str());
00144 
00145                 for (size_t i = 0; i < classes_.size(); i++) {
00146 
00147                         f2 << classes_[i] << "\n";
00148 
00149                 }
00150 
00151                 f2.close();
00152 
00153                 std::ofstream f3((debug_folder_ + "centroids.txt").c_str());
00154 
00155                 for (size_t i = 0; i < centroids_.size(); i++) {
00156 
00157                         f3 << centroids_.points[i].x << " " << centroids_.points[i].y << " "
00158                                         << centroids_.points[i].z << "\n";
00159 
00160                 }
00161 
00162                 f3.close();
00163 
00164         }
00165 
00166         vector<FeatureT> cluster_centers;
00167         vector<int> cluster_labels;
00168 
00169         clusterFeatures(cluster_centers, cluster_labels);
00170 
00171         database_.clear();
00172 
00173         for (size_t i = 0; i < cluster_labels.size(); i++) {
00174 
00175                 FeatureT cluster_center = cluster_centers[cluster_labels[i]];
00176                 std::string classname = classes_[i];
00177 
00178                 database_[cluster_center][classname].points.push_back(centroids_[i]);
00179                 database_[cluster_center][classname].width =
00180                                 database_[cluster_center][classname].points.size();
00181                 database_[cluster_center][classname].height = 1;
00182                 database_[cluster_center][classname].is_dense = true;
00183 
00184                 //ransac_result_threshold_[classname] = 0.01;
00185 
00186                 if (debug_) {
00187                         std::stringstream ss;
00188                         ss << debug_folder_ << "Cluster" << cluster_labels[i] << "/Segment"
00189                                         << i << ".pcd";
00190                         pcl17::io::savePCDFileASCII(ss.str(), *segment_pointclouds_[i]);
00191 
00192                 }
00193 
00194         }
00195 
00196 }
00197 
00198 template<class PointT, class PointNormalT, class FeatureT>
00199 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::computeExternalClassifier(
00200                 const std::string & labels) {
00201 
00202         BOOST_FOREACH(ModelMapValueType &v, class_name_to_partial_views_map_) {
00203                 int view_num_counter = 0;
00204 
00205                 for (size_t i = 0; i < v.second.size(); i++) {
00206                         appendFeaturesFromCloud(v.second[i], v.first, view_num_counter);
00207                         view_num_counter++;
00208 
00209                 }
00210 
00211         }
00212 
00213         // Transform to model centroinds in local coordinate frame of the segment
00214         centroids_.getMatrixXfMap() *= -1;
00215 
00216         normalizeFeatures(features_);
00217 
00218         for (int i = 0; i < num_clusters_; i++) {
00219                 std::stringstream ss;
00220                 ss << debug_folder_ << "Cluster" << i << "/";
00221 
00222                 boost::filesystem::path output_path(ss.str());
00223                 if (boost::filesystem::exists(output_path)) {
00224                         boost::filesystem::remove_all(output_path);
00225                 }
00226 
00227                 boost::filesystem::create_directories(output_path);
00228         }
00229 
00230         std::ofstream f((debug_folder_ + "features.txt").c_str());
00231 
00232         size_t N = sizeof(features_[0].histogram) / sizeof(float);
00233 
00234         for (size_t i = 0; i < features_.size(); i++) {
00235                 for (size_t j = 0; j < N; j++) {
00236                         f << features_[i].histogram[j] << " ";
00237                 }
00238 
00239                 f << "\n";
00240 
00241         }
00242 
00243         f.close();
00244 
00245         std::ofstream f2((debug_folder_ + "classnames.txt").c_str());
00246 
00247         for (size_t i = 0; i < classes_.size(); i++) {
00248 
00249                 f2 << classes_[i] << "\n";
00250 
00251         }
00252 
00253         f2.close();
00254 
00255         std::ofstream f3((debug_folder_ + "centroids.txt").c_str());
00256 
00257         for (size_t i = 0; i < centroids_.size(); i++) {
00258 
00259                 f3 << centroids_.points[i].x << " " << centroids_.points[i].y << " "
00260                                 << centroids_.points[i].z << "\n";
00261 
00262         }
00263 
00264         f3.close();
00265 
00266         vector<int> cluster_labels;
00267         set<int> unique_cluster_labels;
00268         vector<FeatureT> cluster_centers;
00269 
00270         std::ifstream f4(labels.c_str());
00271 
00272         pcl17::PointCloud<FeatureT> mat;
00273         vector<float> bias;
00274 
00275         int feature_size = sizeof(features_[0].histogram) / sizeof(float);
00276 
00277         std::string line;
00278         while (std::getline(f4, line))
00279         //while(f4)
00280 
00281         {
00282 
00283                 // now we'll use a stringstream to separate the fields out of the line
00284                 //std::stringstream ss( line );
00285                 //std::string field;
00286                 FeatureT ff;
00287                 //int i=0;
00288 
00289                 std::vector<std::string> st;
00290                 boost::split(st, line, boost::is_any_of(","), boost::token_compress_on);
00291 
00292                 //std::cerr << "Feature size " << feature_size << " Vector size " << st.size() <<  std::endl;
00293 
00294                 bias.push_back(atof(st[0].c_str()));
00295 
00296                 //while (std::getline( ss, field, ',' ))
00297                 for (size_t i = 0; i < feature_size; i++) {
00298                         // for each field we wish to convert it to a double
00299                         // (since we require that the CSV contains nothing but floating-point values)
00300 
00301                         //std::stringstream fs( field );
00302                         //float v = 0;
00303                         //fs >> v;
00304                         //float v;
00305                         //char tmp;
00306                         //f4 >> v;
00307                         //f4 >> tmp;
00308                         //std::cerr << i << " " << st[i] << std::endl;
00309                         ff.histogram[i] = atof(st[i + 1].c_str());
00310                         //i++;
00311                 }
00312                 mat.points.push_back(ff);
00313                 mat.width = mat.points.size();
00314                 mat.height = 1;
00315         }
00316 
00317         //std::cerr << "Matrix:\n" << mat << std::endl;
00318 
00319         //  while(f4)
00320         //  {
00321         //    FeatureT ff;
00322         //    for(int i=0; i<feature_size; i++)
00323         //    {
00324         //      if (f4.peek() == ',')
00325         //      {
00326         //        f4.ignore();
00327         //      }
00328         //      f4 >> ff.histogram[i];
00329         //    }
00330         //    mat.push_back(ff);
00331         //  }
00332         //
00333         //  std::ofstream f5("mat.txt");
00334         //  for(int i=0; i<mat.points.size(); i++)
00335         //  {
00336         //    for(int j=0; j<feature_size; i++)
00337         //    {
00338         //      f5 << mat.points[i].histogram[j] << ",";
00339         //    }
00340         //    f5 << "\n";
00341         //  }
00342         //  f5.close();
00343 
00344         //TODO check code
00345 
00346         int cluster_size = mat.size();
00347         num_clusters_ = cluster_size;
00348 
00349         for (size_t i = 0; i < features_.size(); i++) {
00350                 Eigen::ArrayXf res = Eigen::ArrayXf::Zero(cluster_size);
00351 
00352                 for (size_t j = 0; j < cluster_size; j++) {
00353                         res[j] += bias[j];
00354                         for (size_t k = 0; k < feature_size; k++) {
00355                                 res[j] += mat[j].histogram[k] * features_[i].histogram[k];
00356                         }
00357                 }
00358 
00359                 int cluster_idx;
00360                 res.maxCoeff(&cluster_idx);
00361                 //std::cerr << "Cluster number " << cluster_idx << std::endl;
00362                 FeatureT ff;
00363 
00364                 for (size_t k = 0; k < feature_size; k++) {
00365                         ff.histogram[k] = 0;
00366                 }
00367 
00368                 ff.histogram[0] = cluster_idx;
00369 
00370                 database_[ff][classes_[i]].push_back(centroids_.points[i]);
00371                 ransac_result_threshold_[classes_[i]] = 0.5;
00372 
00373                 if (debug_) {
00374                         std::stringstream ss;
00375                         ss << debug_folder_ << "Cluster" << cluster_idx << "/Segment" << i
00376                                         << ".pcd";
00377                         pcl17::io::savePCDFileASCII(ss.str(), *segment_pointclouds_[i]);
00378 
00379                 }
00380 
00381         }
00382 
00383         external_classifier_ = labels;
00384 
00385 }
00386 
00387 template<class PointT, class PointNormalT, class FeatureT>
00388 furniture_classification::Hypothesis::Ptr pcl17::PHVObjectClassifier<PointT,
00389                 PointNormalT, FeatureT>::generate_hypothesis(
00390                 std::map<std::string, pcl17::PointCloud<pcl17::PointXYZ>::Ptr> & votes_map) {
00391 
00392         features_.clear();
00393         centroids_.clear();
00394         classes_.clear();
00395         votes_map.clear();
00396 
00397         votes_.clear();
00398         voted_segment_idx_.clear();
00399 
00400         appendFeaturesFromCloud(scene_, "Scene", 0);
00401         normalizeFeaturesWithCurrentMinMax(features_);
00402         vote();
00403 
00404         furniture_classification::Hypothesis::Ptr hp(
00405                         new furniture_classification::Hypothesis);
00406 
00407         for (std::map<std::string, pcl17::PointCloud<pcl17::PointXYZI> >::const_iterator it =
00408                         votes_.begin(); it != votes_.end(); it++) {
00409 
00410                 int grid_center_x, grid_center_y;
00411 
00412                 //std::cerr << it->first << " " << it->second.size() << " votes" << std::endl;
00413 
00414                 Eigen::MatrixXf grid = projectVotesToGrid(it->second, grid_center_x,
00415                                 grid_center_y);
00416 
00417                 PointCloudPtr local_maxima_ = findLocalMaximaInGrid(grid, window_size_);
00418 
00419                 //std::cerr << it->first << " local max " << local_maxima_->size() << std::endl;
00420 
00421                 local_maxima_->header.frame_id = "/base_link";
00422                 votes_map[it->first] = local_maxima_;
00423 
00424                 for (int i = 0; i < local_maxima_->points.size(); i++) {
00425                         geometry_msgs::Pose2D p;
00426                         p.x = local_maxima_->points[i].x;
00427                         p.y = local_maxima_->points[i].y;
00428                         hp->poses.push_back(p);
00429                         hp->classes.push_back(it->first);
00430                 }
00431 
00432         }
00433 
00434         return hp;
00435 }
00436 
00437 template<class PointT, class PointNormalT, class FeatureT> furniture_classification::FittedModelsPtr pcl17::PHVObjectClassifier<
00438                 PointT, PointNormalT, FeatureT>::fit_objects(
00439                 furniture_classification::Hypothesis::ConstPtr hp) {
00440 
00441         pcl17::IterativeClosestPoint<PointNormalT, PointNormalT> icp;
00442         //create point to plane transformationEstimation object
00443         boost::shared_ptr<
00444                         pcl17::registration::TransformationEstimationLM<PointNormalT,
00445                                         PointNormalT> > transformEstPointToPlane(
00446                         new pcl17::registration::TransformationEstimationLM<PointNormalT,
00447                                         PointNormalT>());
00448         //icp.setTransformationEstimation(transformEstPointToPlane);
00449         icp.setMaximumIterations(icp_max_iterations_);
00450         icp.setMaxCorrespondenceDistance(icp_max_correspondence_distance_);
00451 
00452         icp.setEuclideanFitnessEpsilon(0);
00453 
00454         //pcl17::IterativeClosestPoint<PointNormalT, PointNormalT> icp;
00455         icp.setInputTarget(scene_);
00456 
00457         furniture_classification::FittedModelsPtr res(new furniture_classification::FittedModels);
00458         //PointNormalCloudPtr res(new PointNormalCloud);
00459         //res->header.frame_id = "/base_link";
00460 
00461         std::map<std::string, vector<PointNormalCloudPtr> > result_vector_map;
00462         std::map<std::string, vector<float> > scores_map;
00463 
00464         for (int i = 0; i < hp->poses.size(); i++) {
00465 
00466                 PointNormalCloudPtr best_fit(new PointNormalCloud);
00467                 double min_fittness = std::numeric_limits<double>::max();
00468 
00469                 for (int j = 0;
00470                                 j < class_name_to_full_models_map_[hp->classes[i]].size();
00471                                 j++) {
00472 
00473                         for (int angle_idx = 0; angle_idx < num_angles_; angle_idx++) {
00474 
00475                                 double angle = (angle_idx * 2 * M_PI) / num_angles_;
00476 
00477                                 PointNormalCloudPtr cloud_transformed(new PointNormalCloud);
00478 
00479                                 Eigen::Affine3f transform;
00480                                 transform.setIdentity();
00481                                 Eigen::Translation<float, 3> translation(hp->poses[i].x,
00482                                                 hp->poses[i].y, 0);
00483                                 Eigen::AngleAxis<float> rotation(angle,
00484                                                 Eigen::Vector3f(0, 0, 1));
00485                                 transform *= rotation;
00486                                 transform *= translation;
00487 
00488                                 pcl17::transformPointCloud(
00489                                                 *class_name_to_full_models_map_[hp->classes[i]][j],
00490                                                 *cloud_transformed, transform);
00491 
00492                                 icp.setInputSource(cloud_transformed);
00493                                 PointNormalCloudPtr Final(new PointNormalCloud);
00494                                 icp.align(*Final);
00495 
00496                                 double score = icp.getFitnessScore();
00497                                 //std::cerr << i << " " << j << " " << score << std::endl;
00498                                 if (score < min_fittness) {
00499                                         best_fit = Final;
00500                                         min_fittness = score;
00501                                 }
00502 
00503                         }
00504                 }
00505 
00506                 if (min_fittness < ransac_result_threshold_[hp->classes[i]]) {
00507                         result_vector_map[hp->classes[i]].push_back(best_fit);
00508                         scores_map[hp->classes[i]].push_back(min_fittness);
00509                 }
00510 
00511         }
00512 
00513         typename std::map<std::string, vector<PointNormalCloudPtr> >::iterator it;
00514 
00515         for (it = result_vector_map.begin(); it != result_vector_map.end(); it++) {
00516 
00517                 vector<float> scores;
00518                 vector<PointNormalCloudPtr> result_vector = removeIntersecting(
00519                                 it->second, scores_map[it->first], &scores);
00520 
00521                 for (int i = 0; i < result_vector.size(); i++) {
00522                         sensor_msgs::PointCloud2 r;
00523                         pcl17::toROSMsg(*result_vector[i], r);
00524                         res->models.push_back(r);
00525                         res->scores.push_back(scores[i]);
00526                         res->classes.push_back(it->first);
00527                         //*res += *result_vector[i];
00528                 }
00529 
00530         }
00531 
00532         return res;
00533 
00534 }
00535 
00536 template<class PointT, class PointNormalT, class FeatureT>
00537 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::classify() {
00538         appendFeaturesFromCloud(scene_, "Scene", 0);
00539         normalizeFeaturesWithCurrentMinMax(features_);
00540         vote();
00541 
00542         RandomSampleConsensusSimple<PointNormalT> ransac(
00543                         subsampling_resolution_ * 2);
00544 
00545         ransac.setScene(scene_);
00546         ransac.setMaxIterations(ransac_num_iter_);
00547         ransac.setWeight(ransac_vis_score_weight_);
00548 
00549         for (std::map<std::string, pcl17::PointCloud<pcl17::PointXYZI> >::const_iterator it =
00550                         votes_.begin(); it != votes_.end(); it++) {
00551 
00552                 std::cerr << "Checking for " << it->first << std::endl;
00553                 pcl17::io::savePCDFileASCII(debug_folder_ + it->first + "_votes.pcd",
00554                                 it->second);
00555 
00556                 int grid_center_x, grid_center_y;
00557                 Eigen::MatrixXf grid = projectVotesToGrid(it->second, grid_center_x,
00558                                 grid_center_y);
00559 
00560                 if (debug_) {
00561                         Eigen::MatrixXi img = (grid * 255.0 / grid.maxCoeff()).cast<int>();
00562 
00563                         std::stringstream filename;
00564                         filename << debug_folder_ << it->first << "_center_"
00565                                         << grid_center_x << "_" << grid_center_y << ".pgm";
00566                         std::ofstream f(filename.str().c_str());
00567                         f << "P2\n" << grid.cols() << " " << grid.rows() << "\n255\n";
00568                         f << img;
00569                 }
00570 
00571                 vector<PointNormalCloudPtr> result;
00572                 vector<float> scores;
00573 
00574                 BOOST_FOREACH(PointNormalCloudPtr & full_model, class_name_to_full_models_map_[it->first]) {
00575                         PointNormalT minp, maxp;
00576                         pcl17::getMinMax3D<PointNormalT>(*full_model, minp, maxp);
00577                         float window_size = std::max((maxp.x - minp.x), (maxp.y - minp.y))
00578                                         / 2;
00579 
00580                         std::cerr << "Window size " << window_size << std::endl;
00581 
00582                         ransac.setModel(full_model);
00583 
00584                         PointCloudPtr local_maxima_ = findLocalMaximaInGrid(grid,
00585                                         window_size);
00586 
00587                         if (debug_ && !local_maxima_->empty())
00588                                 pcl17::io::savePCDFileASCII(
00589                                                 debug_folder_ + it->first + "_local_maxima.pcd",
00590                                                 *local_maxima_);
00591 
00592                         vector<boost::shared_ptr<std::vector<int> > > voted_segments;
00593                         voted_segments = findVotedSegments(local_maxima_, it->first,
00594                                         window_size);
00595 
00596                         fitModelsWithRansac(voted_segments, it->first, ransac, result,
00597                                         scores);
00598 
00599                 }
00600 
00601                 //generateVisibilityScore(result, scores);
00602                 result = removeIntersecting(result, scores);
00603 
00604                 found_objects_[it->first] = result;
00605 
00606         }
00607 
00608 }
00609 
00610 template<class PointT, class PointNormalT, class FeatureT>
00611 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::eval_clustering(
00612                 const std::string & classname, const float search_radius, double &tp,
00613                 double &fn, double &fp) {
00614         appendFeaturesFromCloud(scene_, "Scene", 0);
00615         normalizeFeaturesWithCurrentMinMax(features_);
00616         vote();
00617 
00618         for (std::map<std::string, pcl17::PointCloud<pcl17::PointXYZI> >::const_iterator it =
00619                         votes_.begin(); it != votes_.end(); it++) {
00620 
00621                 //std::cerr << "Checking for " << it->first << std::endl;
00622                 //pcl17::io::savePCDFileASCII(debug_folder_ + it->first + "_votes.pcd", it->second);
00623 
00624                 int grid_center_x, grid_center_y;
00625                 Eigen::MatrixXf grid = projectVotesToGrid(it->second, grid_center_x,
00626                                 grid_center_y);
00627 
00628                 BOOST_FOREACH (PointNormalCloudPtr & full_model, class_name_to_full_models_map_[it->first]) {
00629                         PointNormalT minp, maxp;
00630                         pcl17::getMinMax3D<PointNormalT>(*full_model, minp, maxp);
00631                         float window_size = std::max((maxp.x - minp.x), (maxp.y - minp.y))
00632                                         / 2;
00633 
00634                         Eigen::ArrayXXi local_max = getLocalMaximaGrid(grid, window_size);
00635 
00636                         int ctp, cfp, cfn;
00637                         int search_radius_pixels = search_radius / cell_size_;
00638 
00639                         if (it->first == classname) {
00640 
00641                                 Eigen::ArrayXXi true_region = local_max.block(
00642                                                 grid_center_x - search_radius_pixels,
00643                                                 grid_center_y - search_radius_pixels,
00644                                                 2 * search_radius_pixels + 1,
00645                                                 2 * search_radius_pixels + 1);
00646 
00647                                 ctp = (true_region == 1).count();
00648                                 cfn = (ctp == 0);
00649                                 cfp = (local_max == 1).count() - ctp;
00650 
00651                         } else {
00652                                 cfp = (local_max == 1).count();
00653                                 ctp = 0;
00654                                 cfn = 0;
00655                         }
00656 
00657                         tp += ctp;
00658                         fp += cfp;
00659                         fn += cfn;
00660 
00661                 }
00662 
00663         }
00664 
00665 }
00666 
00667 template<class PointT, class PointNormalT, class FeatureT>
00668 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::eval_clustering_external(
00669                 const std::string & classname, const float search_radius, double &tp,
00670                 double &fn, double &fp, const std::string & matrix) {
00671 
00672         features_.clear();
00673         classes_.clear();
00674         centroids_.clear();
00675 
00676         appendFeaturesFromCloud(scene_, "Scene", 0);
00677         normalizeFeaturesWithCurrentMinMax(features_);
00678         vote_external(matrix);
00679 
00680         for (std::map<std::string, pcl17::PointCloud<pcl17::PointXYZI> >::const_iterator it =
00681                         votes_.begin(); it != votes_.end(); it++) {
00682 
00683                 //std::cerr << "Checking for " << it->first << std::endl;
00684                 //pcl17::io::savePCDFileASCII(debug_folder_ + it->first + "_votes.pcd", it->second);
00685 
00686                 int grid_center_x, grid_center_y;
00687                 Eigen::MatrixXf grid = projectVotesToGrid(it->second, grid_center_x,
00688                                 grid_center_y);
00689 
00690                 BOOST_FOREACH (PointNormalCloudPtr & full_model, class_name_to_full_models_map_[it->first]) {
00691                         PointNormalT minp, maxp;
00692                         pcl17::getMinMax3D<PointNormalT>(*full_model, minp, maxp);
00693                         float window_size = std::max((maxp.x - minp.x), (maxp.y - minp.y))
00694                                         / 2;
00695 
00696                         Eigen::ArrayXXi local_max = getLocalMaximaGrid(grid, window_size);
00697 
00698                         int ctp, cfp, cfn;
00699                         int search_radius_pixels = search_radius / cell_size_;
00700 
00701                         if (it->first == classname) {
00702 
00703                                 Eigen::ArrayXXi true_region = local_max.block(
00704                                                 grid_center_x - search_radius_pixels,
00705                                                 grid_center_y - search_radius_pixels,
00706                                                 2 * search_radius_pixels + 1,
00707                                                 2 * search_radius_pixels + 1);
00708 
00709                                 ctp = (true_region == 1).count();
00710                                 cfn = (ctp == 0);
00711                                 cfp = (local_max == 1).count() - ctp;
00712 
00713                         } else {
00714                                 cfp = (local_max == 1).count();
00715                                 ctp = 0;
00716                                 cfn = 0;
00717                         }
00718 
00719                         tp += ctp;
00720                         fp += cfp;
00721                         fn += cfn;
00722 
00723                 }
00724 
00725         }
00726 
00727 }
00728 
00729 template<class PointT, class PointNormalT, class FeatureT>
00730 typename pcl17::PointCloud<PointNormalT>::Ptr pcl17::PHVObjectClassifier<PointT,
00731                 PointNormalT, FeatureT>::estimateNormalsAndSubsample(
00732                 typename pcl17::PointCloud<PointT>::ConstPtr cloud_orig) {
00733 
00734         //std::vector<int> idx;
00735         //PointCloudPtr cloud(new PointCloud);
00736         //pcl17::removeNaNFromPointCloud(*cloud_orig, *cloud, idx);
00737 
00738         PointNormalCloudPtr cloud_with_normals(new PointNormalCloud);
00739         PointNormalCloudPtr cloud_downsampled(new PointNormalCloud);
00740 
00741         //    pcl17::VoxelGrid<PointT> grid;
00742         //    grid.setInputCloud(cloud_orig);
00743         //    grid.setLeafSize(subsampling_resolution_, subsampling_resolution_, subsampling_resolution_);
00744         //    grid.filter(*cloud_downsampled);
00745 
00746         PointTreePtr tree(new PointTree);
00747 
00748         mls_->setComputeNormals(true);
00749 
00750         mls_->setInputCloud(cloud_orig);
00751         mls_->setPolynomialFit(mls_polynomial_fit_);
00752         mls_->setPolynomialOrder(mls_polynomial_order_);
00753         mls_->setSearchMethod(tree);
00754         mls_->setSearchRadius(mls_search_radius_);
00755 
00756         this->mls_->process(*cloud_with_normals);
00757 
00758         pcl17::VoxelGrid<PointNormalT> grid;
00759         grid.setInputCloud(cloud_with_normals);
00760         grid.setLeafSize(subsampling_resolution_, subsampling_resolution_,
00761                         subsampling_resolution_);
00762         grid.filter(*cloud_downsampled);
00763 
00764         Eigen::Vector4f so = cloud_orig->sensor_origin_;
00765         //std::cerr << "Model viewpoint\n" << so << std::endl;
00766         for (size_t i = 0; i < cloud_downsampled->points.size(); i++) {
00767 
00768                 pcl17::flipNormalTowardsViewpoint(cloud_downsampled->points[i], so[0],
00769                                 so[1], so[2], cloud_downsampled->points[i].normal_x,
00770                                 cloud_downsampled->points[i].normal_y,
00771                                 cloud_downsampled->points[i].normal_z);
00772         }
00773 
00774         //cloud_downsampled->is_dense = false;
00775         //pcl17::removeNaNFromPointCloud(*cloud_downsampled, *cloud_downsampled, idx);
00776 
00777         cloud_downsampled->sensor_origin_ = cloud_orig->sensor_origin_;
00778         cloud_downsampled->sensor_orientation_ = cloud_orig->sensor_orientation_;
00779 
00780         return cloud_downsampled;
00781 
00782 }
00783 
00784 template<class PointT, class PointNormalT, class FeatureT>
00785 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::getSegmentsFromCloud(
00786                 PointNormalCloudPtr cloud_with_normals,
00787                 vector<boost::shared_ptr<vector<int> > > & segment_indices,
00788                 pcl17::PointCloud<pcl17::PointXYZRGBNormal>::Ptr & colored_segments) {
00789 
00790         segment_indices.clear();
00791 
00792         PointCloudPtr cloud(new PointCloud);
00793         pcl17::PointCloud<pcl17::Normal>::Ptr normals(
00794                         new pcl17::PointCloud<pcl17::Normal>);
00795         pcl17::copyPointCloud(*cloud_with_normals, *cloud);
00796         pcl17::copyPointCloud(*cloud_with_normals, *normals);
00797 
00798         PointTreePtr tree(new PointTree);
00799 
00800         vector<pcl17::PointIndices> segment_indices_all;
00801 
00802         pcl17::RegionGrowing<PointT, pcl17::Normal> region_growing;
00803         region_growing.setMinClusterSize(min_points_in_segment_);
00804         //region_growing.setMaxClusterSize (10000);
00805         region_growing.setSearchMethod(tree);
00806         region_growing.setNumberOfNeighbours(30);
00807         region_growing.setInputCloud(cloud);
00808         //region_growing.setIndices (indices);
00809         region_growing.setInputNormals(normals);
00810         region_growing.setSmoothnessThreshold(rg_smoothness_threshold_);
00811         region_growing.setResidualThreshold(rg_residual_threshold_);
00812         region_growing.setCurvatureThreshold(1.0);
00813         region_growing.setCurvatureTestFlag(false);
00814         region_growing.setSmoothModeFlag(false);
00815         region_growing.setResidualTestFlag(true);
00816 
00817         //segment_indices_all = region_growing.getSegments();
00818         region_growing.extract(segment_indices_all);
00819 
00820         BOOST_FOREACH(pcl17::PointIndices & i, segment_indices_all) {
00821                 if ((int) i.indices.size() > min_points_in_segment_) {
00822                         boost::shared_ptr<vector<int> > indices(new vector<int>);
00823                         *indices = i.indices;
00824                         segment_indices.push_back(indices);
00825                 }
00826         }
00827 
00828         if (debug_) {
00829                 pcl17::PointCloud<pcl17::PointXYZRGB>::Ptr colored_segments_all;
00830                 colored_segments_all = region_growing.getColoredCloud();
00831 
00832                 vector<int> valid_segment_indices;
00833 
00834                 BOOST_FOREACH(boost::shared_ptr<vector<int> > & i, segment_indices) {
00835                         valid_segment_indices.insert(valid_segment_indices.begin(),
00836                                         i->begin(), i->end());
00837                 }
00838 
00839                 colored_segments.reset(new pcl17::PointCloud<pcl17::PointXYZRGBNormal>);
00840 
00841                 for (size_t j = 0; j < valid_segment_indices.size(); j++) {
00842                         pcl17::PointXYZRGBNormal p;
00843                         int i = valid_segment_indices[j];
00844                         p.x = colored_segments_all->points[i].x;
00845                         p.y = colored_segments_all->points[i].y;
00846                         p.z = colored_segments_all->points[i].z;
00847                         p.normal_x = normals->points[i].normal_x;
00848                         p.normal_y = normals->points[i].normal_y;
00849                         p.normal_z = normals->points[i].normal_z;
00850                         p.rgb = colored_segments_all->points[i].rgb;
00851                         colored_segments->push_back(p);
00852                 }
00853 
00854                 colored_segments->sensor_origin_ = cloud_with_normals->sensor_origin_;
00855                 colored_segments->sensor_orientation_ =
00856                                 cloud_with_normals->sensor_orientation_;
00857 
00858         }
00859 
00860 }
00861 
00862 template<class PointT, class PointNormalT, class FeatureT>
00863 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::appendFeaturesFromCloud(
00864                 PointNormalCloudPtr & cloud, const string & class_name, const int i) {
00865         if (debug_) {
00866                 std::stringstream ss;
00867                 ss << debug_folder_ << class_name << i << ".pcd";
00868                 std::cerr << "Writing to file " << ss.str() << std::endl;
00869                 pcl17::io::savePCDFileASCII(ss.str(), *cloud);
00870 
00871         }
00872 
00873         pcl17::PointCloud<pcl17::PointXYZRGBNormal>::Ptr colored_segments;
00874         vector<boost::shared_ptr<vector<int> > > segment_indices;
00875         getSegmentsFromCloud(cloud, segment_indices, colored_segments);
00876 
00877         segment_indices_ = segment_indices;
00878 
00879         PointNormalTreePtr tree(new PointNormalTree);
00880 
00881         feature_estimator_->setSearchMethod(tree);
00882         feature_estimator_->setKSearch(fe_k_neighbours_);
00883         feature_estimator_->setInputCloud(cloud);
00884 
00885         typename pcl17::VFHEstimation<PointNormalT, PointNormalT, FeatureT>::Ptr f =
00886                         boost::dynamic_pointer_cast<
00887                                         pcl17::VFHEstimation<PointNormalT, PointNormalT, FeatureT> >(
00888                                         feature_estimator_);
00889 
00890         if (f) {
00891                 f->setInputNormals(cloud);
00892                 f->setKSearch(20);
00893                 f->setViewPoint(cloud->sensor_origin_[0], cloud->sensor_origin_[1],
00894                                 cloud->sensor_origin_[2]);
00895         }
00896 
00897         BOOST_FOREACH(const boost::shared_ptr<vector<int> > & idx, segment_indices) { // compute deature for segment
00898                 pcl17::PointCloud<FeatureT> feature;
00899                 //PointNormalCloudPtr p(new PointNormalCloud(*cloud, *idx));
00900                 //feature_estimator_->setInputCloud(p);
00901                 feature_estimator_->setIndices(idx);
00902                 feature_estimator_->compute(feature);
00903 
00904                 // Compute centroid of segment
00905                 Eigen::Vector4f centroid;
00906                 pcl17::compute3DCentroid(*cloud, *idx, centroid);
00907                 PointT centroid_point;
00908                 centroid_point.x = centroid[0];
00909                 centroid_point.y = centroid[1];
00910                 centroid_point.z = centroid[2];
00911 
00912                 features_.push_back(feature.points[0]);
00913                 centroids_.points.push_back(centroid_point);
00914                 classes_.push_back(class_name);
00915 
00916                 if (debug_) {
00917                         PointNormalCloudPtr segm(new PointNormalCloud(*cloud, *idx));
00918                         segment_pointclouds_.push_back(segm);
00919                 }
00920 
00921         }
00922 
00923         centroids_.width = centroids_.points.size();
00924         centroids_.height = 1;
00925         centroids_.is_dense = true;
00926 
00927         // if debug dump partial views and segmentations
00928         if (debug_) {
00929                 std::stringstream ss;
00930                 ss << debug_folder_ << class_name << i << "_segmentation.pcd";
00931                 std::cerr << "Writing to file " << ss.str() << std::endl;
00932                 pcl17::io::savePCDFileASCII(ss.str(), *colored_segments);
00933         }
00934 }
00935 
00936 template<class PointT, class PointNormalT, class FeatureT>
00937 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::normalizeFeatures(
00938                 std::vector<FeatureT> & features) {
00939 
00940         int N = sizeof(min_.histogram) / sizeof(float);
00941 
00942         // Init max and min vales with first feature
00943         for (int j = 0; j < N; j++) {
00944                 min_.histogram[j] = features[0].histogram[j];
00945                 max_.histogram[j] = features[0].histogram[j];
00946         }
00947 
00948         // Find max and min values
00949         for (size_t i = 0; i < features.size(); i++) {
00950                 for (int j = 0; j < N; j++) {
00951                         if (features[i].histogram[j] < min_.histogram[j])
00952                                 min_.histogram[j] = features[i].histogram[j];
00953                         if (features[i].histogram[j] > max_.histogram[j])
00954                                 max_.histogram[j] = features[i].histogram[j];
00955                 }
00956         }
00957 
00958         // Normalize
00959         for (size_t i = 0; i < features.size(); i++) {
00960                 for (int j = 0; j < N; j++) {
00961                         if ((max_.histogram[j] - min_.histogram[j]) != 0) {
00962                                 features[i].histogram[j] = (features[i].histogram[j]
00963                                                 - min_.histogram[j])
00964                                                 / (max_.histogram[j] - min_.histogram[j]);
00965                         }
00966                 }
00967         }
00968 
00969 }
00970 
00971 template<class PointT, class PointNormalT, class FeatureT>
00972 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::normalizeFeaturesWithCurrentMinMax(
00973                 std::vector<FeatureT> & features) {
00974         int N = sizeof(min_.histogram) / sizeof(float);
00975 
00976         FeatureT min = min_, max = max_;
00977 
00978         // Find max and min values
00979         for (size_t i = 0; i < features.size(); i++) {
00980                 for (int j = 0; j < N; j++) {
00981                         if (features[i].histogram[j] < min.histogram[j])
00982                                 min.histogram[j] = features[i].histogram[j];
00983                         if (features[i].histogram[j] > max.histogram[j])
00984                                 max.histogram[j] = features[i].histogram[j];
00985                 }
00986         }
00987 
00988         // Normalize
00989         for (size_t i = 0; i < features.size(); i++) {
00990                 for (int j = 0; j < N; j++) {
00991                         if ((max_.histogram[j] - min_.histogram[j]) != 0) {
00992                                 features[i].histogram[j] = (features[i].histogram[j]
00993                                                 - min.histogram[j])
00994                                                 / (max.histogram[j] - min.histogram[j]);
00995                         }
00996                 }
00997         }
00998 
00999 }
01000 
01001 template<class PointT, class PointNormalT, class FeatureT>
01002 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::vote() {
01003 
01004         pcl17::search::KdTree<FeatureT> feature_search;
01005         feature_search.setInputCloud(database_features_cloud_);
01006 
01007         for (size_t i = 0; i < features_.size(); i++) {
01008                 std::vector<int> indices;
01009                 std::vector<float> distances;
01010                 feature_search.nearestKSearch(features_[i], num_neighbours_, indices,
01011                                 distances);
01012 
01013                 if (debug_) {
01014                         std::stringstream ss;
01015                         ss << debug_folder_ << "Segment" << i << ".pcd";
01016                         PointNormalCloud p(*scene_, *segment_indices_[i]);
01017                         pcl17::io::savePCDFileASCII(ss.str(), p);
01018                 }
01019 
01020                 for (size_t j = 0; j < indices.size(); j++) {
01021 
01022                         FeatureT closest_cluster = database_features_cloud_->at(indices[j]);
01023                         for (std::map<std::string, pcl17::PointCloud<pcl17::PointXYZ> >::const_iterator it =
01024                                         database_[closest_cluster].begin();
01025                                         it != database_[closest_cluster].end(); it++) {
01026 
01027                                 std::string class_name = it->first;
01028                                 PointCloud model_centers = it->second;
01029                                 PointCloud model_centers_transformed;
01030                                 pcl17::PointCloud<pcl17::PointXYZI> model_centers_transformed_weighted;
01031 
01032                                 Eigen::Affine3f transform;
01033                                 transform.setIdentity();
01034                                 transform.translate(centroids_[i].getVector3fMap());
01035                                 pcl17::transformPointCloud(model_centers,
01036                                                 model_centers_transformed, transform);
01037 
01038                                 pcl17::copyPointCloud(model_centers_transformed,
01039                                                 model_centers_transformed_weighted);
01040 
01041                                 // TODO revise weighting function
01042                                 for (size_t k = 0;
01043                                                 k < model_centers_transformed_weighted.size(); k++) {
01044                                         model_centers_transformed_weighted.points[k].intensity =
01045                                                         exp(-(distances[j] * distances[j]))
01046                                                                         * (1.0 / model_centers.size());
01047                                         voted_segment_idx_[class_name].push_back(i);
01048                                 }
01049 
01050                                 if (debug_) {
01051                                         std::stringstream ss;
01052                                         ss << debug_folder_ << "Segment" << i << "_neighbour" << j
01053                                                         << "_" << class_name << "_votes.pcd";
01054                                         pcl17::io::savePCDFileASCII(ss.str(),
01055                                                         model_centers_transformed_weighted);
01056                                 }
01057 
01058                                 votes_[class_name] += model_centers_transformed_weighted;
01059                         }
01060                 }
01061 
01062         }
01063 
01064 }
01065 
01066 template<class PointT, class PointNormalT, class FeatureT>
01067 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::vote_external(
01068                 const std::string & matrix) {
01069 
01070         std::ifstream f4(matrix.c_str());
01071 
01072         pcl17::PointCloud<FeatureT> mat;
01073         std::vector<float> bias;
01074 
01075         int feature_size = sizeof(features_[0].histogram) / sizeof(float);
01076 
01077         std::string line;
01078         while (std::getline(f4, line))
01079         //while(f4)
01080         {
01081 
01082                 // now we'll use a stringstream to separate the fields out of the line
01083                 //std::stringstream ss( line );
01084                 //std::string field;
01085                 FeatureT ff;
01086                 //int i=0;
01087 
01088                 std::vector<std::string> st;
01089                 boost::split(st, line, boost::is_any_of(","), boost::token_compress_on);
01090 
01091                 //std::cerr << "Feature size " << feature_size << " Vector size " << st.size() <<  std::endl;
01092 
01093                 bias.push_back(atof(st[0].c_str()));
01094 
01095                 //while (std::getline( ss, field, ',' ))
01096                 for (size_t i = 0; i < feature_size; i++) {
01097                         // for each field we wish to convert it to a double
01098                         // (since we require that the CSV contains nothing but floating-point values)
01099 
01100                         //std::stringstream fs( field );
01101                         //float v = 0;
01102                         //fs >> v;
01103                         //float v;
01104                         //char tmp;
01105                         //f4 >> v;
01106                         //f4 >> tmp;
01107                         //std::cerr << i << " " << st[i] << std::endl;
01108                         ff.histogram[i] = atof(st[i + 1].c_str());
01109                         //i++;
01110                 }
01111                 mat.points.push_back(ff);
01112                 mat.width = mat.points.size();
01113                 mat.height = 1;
01114         }
01115 
01116         //    string line;
01117         //    while (getline(f4, line))
01118         //    {
01119         //
01120         //      // now we'll use a stringstream to separate the fields out of the line
01121         //      stringstream ss(line);
01122         //      string field;
01123         //      FeatureT ff;
01124         //      int i = 0;
01125         //
01126         //      while (getline(ss, field, ','))
01127         //      {
01128         //        // for each field we wish to convert it to a double
01129         //        // (since we require that the CSV contains nothing but floating-point values)
01130         //        stringstream fs(field);
01131         //        float v = 0;
01132         //        fs >> v;
01133         //        ff.histogram[i] = v;
01134         //        i++;
01135         //      }
01136         //      mat.points.push_back(ff);
01137         //      mat.width = mat.points.size();
01138         //      mat.height = 1;
01139         //    }
01140 
01141         //pcl17::search::KdTree<FeatureT> feature_search;
01142         //feature_search.setInputCloud(database_features_cloud_);
01143 
01144         for (size_t i = 0; i < features_.size(); i++) {
01145                 //std::vector<int> indices;
01146                 //std::vector<float> distances;
01147                 //feature_search.nearestKSearch(features_[i], num_neighbours_, indices, distances);
01148 
01149                 Eigen::ArrayXf res = Eigen::ArrayXf::Zero(mat.points.size());
01150 
01151                 for (size_t j = 0; j < mat.points.size(); j++) {
01152                         res[j] += bias[j];
01153                         for (size_t k = 0; k < feature_size; k++) {
01154                                 res[j] += mat[j].histogram[k] * features_[i].histogram[k];
01155                         }
01156                 }
01157 
01158                 int cluster_idx;
01159                 res.maxCoeff(&cluster_idx);
01160                 //std::cerr << "Cluster number " << cluster_idx << std::endl;
01161                 FeatureT ff;
01162 
01163                 for (size_t k = 0; k < feature_size; k++) {
01164                         ff.histogram[k] = 0;
01165                 }
01166 
01167                 ff.histogram[0] = cluster_idx;
01168 
01169                 float prob = exp(res[cluster_idx]) / res.exp().sum();
01170 
01171                 if (debug_) {
01172                         std::stringstream ss;
01173                         ss << debug_folder_ << "Segment" << i << ".pcd";
01174                         PointNormalCloud p(*scene_, *segment_indices_[i]);
01175                         pcl17::io::savePCDFileASCII(ss.str(), p);
01176                 }
01177 
01178                 //for (size_t j = 0; j < indices.size(); j++)
01179                 //{
01180 
01181                 //FeatureT closest_cluster = database_features_cloud_->at(indices[j]);
01182                 for (std::map<std::string, pcl17::PointCloud<pcl17::PointXYZ> >::const_iterator it =
01183                                 database_[ff].begin(); it != database_[ff].end(); it++) {
01184 
01185                         std::string class_name = it->first;
01186                         PointCloud model_centers = it->second;
01187                         PointCloud model_centers_transformed;
01188                         pcl17::PointCloud<pcl17::PointXYZI> model_centers_transformed_weighted;
01189 
01190                         Eigen::Affine3f transform;
01191                         transform.setIdentity();
01192                         transform.translate(centroids_[i].getVector3fMap());
01193                         pcl17::transformPointCloud(model_centers, model_centers_transformed,
01194                                         transform);
01195 
01196                         pcl17::copyPointCloud(model_centers_transformed,
01197                                         model_centers_transformed_weighted);
01198 
01199                         // TODO revise weighting function
01200                         for (size_t k = 0; k < model_centers_transformed_weighted.size();
01201                                         k++) {
01202                                 model_centers_transformed_weighted.points[k].intensity = prob
01203                                                 * (1.0 / model_centers.size());
01204                                 voted_segment_idx_[class_name].push_back(i);
01205                         }
01206 
01207                         //          if (debug_)
01208                         //          {
01209                         //            std::stringstream ss;
01210                         //            ss << debug_folder_ << "Segment" << i << "_neighbour" << j << "_" << class_name << "_votes.pcd";
01211                         //            pcl17::io::savePCDFileASCII(ss.str(), model_centers_transformed_weighted);
01212                         //          }
01213 
01214                         votes_[class_name] += model_centers_transformed_weighted;
01215                         //}
01216                 }
01217 
01218         }
01219 
01220 }
01221 
01222 template<class PointT, class PointNormalT, class FeatureT>
01223 Eigen::MatrixXf pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::projectVotesToGrid(
01224                 const pcl17::PointCloud<pcl17::PointXYZI> & model_centers,
01225                 int & grid_center_x, int & grid_center_y) {
01226 
01227         Eigen::MatrixXf grid;
01228 
01229         int image_x_width = (int) ((max_scene_bound_.x - min_scene_bound_.x)
01230                         / cell_size_);
01231         int image_y_width = (int) ((max_scene_bound_.y - min_scene_bound_.y)
01232                         / cell_size_);
01233 
01234         grid = Eigen::MatrixXf::Zero(image_x_width, image_y_width);
01235 
01236         for (size_t i = 0; i < model_centers.points.size(); i++) {
01237                 int vote_x = (model_centers.points[i].x - min_scene_bound_.x)
01238                                 / cell_size_;
01239                 int vote_y = (model_centers.points[i].y - min_scene_bound_.y)
01240                                 / cell_size_;
01241                 if ((vote_x >= 0) && (vote_y >= 0) && (vote_x < image_x_width)
01242                                 && (vote_y < image_y_width) && (model_centers.points[i].z >= 0))
01243                         grid(vote_x, vote_y) += model_centers.points[i].intensity;
01244         }
01245 
01246         grid_center_x = -min_scene_bound_.x / cell_size_;
01247         grid_center_y = -min_scene_bound_.y / cell_size_;
01248 
01249         return grid;
01250 }
01251 
01252 template<class PointT, class PointNormalT, class FeatureT>
01253 typename pcl17::PointCloud<PointT>::Ptr pcl17::PHVObjectClassifier<PointT,
01254                 PointNormalT, FeatureT>::findLocalMaximaInGrid(Eigen::MatrixXf grid,
01255                 float window_size) {
01256 
01257         PointCloudPtr local_maxima(new PointCloud);
01258 
01259         float max, min;
01260         max = grid.maxCoeff();
01261         min = grid.minCoeff();
01262 
01263         float threshold = min + (max - min) * local_maxima_threshold_;
01264         //float threshold = local_maxima_threshold_;
01265 
01266         //std::cerr << max << " " << min << " " << local_maxima_threshold_ << " " << threshold << std::endl;
01267 
01268         int window_size_pixels = window_size / cell_size_;
01269 
01270         if (window_size_pixels >= std::min(grid.cols() - 3, grid.rows() - 3)) {
01271                 window_size_pixels = std::min(grid.cols() - 3, grid.rows() - 3);
01272         }
01273 
01274         // Make window_size_pixels even
01275         if (window_size_pixels % 2 == 0)
01276                 window_size_pixels++;
01277 
01278         int side = window_size_pixels / 2;
01279 
01280         for (int i = 0; i < grid.rows(); i++) {
01281                 for (int j = 0; j < grid.cols(); j++) {
01282 
01283                         //float max;
01284                         //Eigen::MatrixXf window = grid.block(i - side, j - side, window_size_pixels, window_size_pixels);
01285                         //max = window.maxCoeff();
01286 
01287                         //assert(window.cols() == window_size_pixels);
01288                         //assert(window.rows() == window_size_pixels);
01289 
01290                         // if max of the window is in its center then this point is local maxima
01291                         if (/*(max == grid(i, j)) && (max > 0) &&*/(grid(i, j) > threshold)) {
01292                                 PointT point;
01293                                 point.x = i * cell_size_ + min_scene_bound_.x;
01294                                 point.y = j * cell_size_ + min_scene_bound_.y;
01295                                 point.z = 0;
01296                                 local_maxima->points.push_back(point);
01297                         }
01298                 }
01299         }
01300 
01301         local_maxima->width = local_maxima->points.size();
01302         local_maxima->height = 1;
01303         local_maxima->is_dense = true;
01304 
01305         return local_maxima;
01306 
01307 }
01308 
01309 template<class PointT, class PointNormalT, class FeatureT>
01310 typename Eigen::ArrayXXi pcl17::PHVObjectClassifier<PointT, PointNormalT,
01311                 FeatureT>::getLocalMaximaGrid(Eigen::MatrixXf & grid,
01312                 float window_size) {
01313 
01314         Eigen::ArrayXXi local_max = Eigen::ArrayXXi::Zero(grid.rows(), grid.cols());
01315 
01316         float max, min;
01317         max = grid.maxCoeff();
01318         min = grid.minCoeff();
01319 
01320         //std::cerr << min << " " << max << std::endl;
01321         float threshold = min + (max - min) * local_maxima_threshold_;
01322         //float threshold = local_maxima_threshold_;
01323 
01324         int window_size_pixels = window_size / cell_size_;
01325 
01326         if (window_size_pixels >= std::min(grid.cols() - 3, grid.rows() - 3)) {
01327                 window_size_pixels = std::min(grid.cols() - 3, grid.rows() - 3);
01328         }
01329 
01330         // Make window_size_pixels even
01331         if (window_size_pixels % 2 == 0)
01332                 window_size_pixels++;
01333 
01334         int side = window_size_pixels / 2;
01335 
01336         for (int i = side; i < (grid.rows() - side); i++) {
01337                 for (int j = side; j < (grid.cols() - side); j++) {
01338 
01339                         float max;
01340                         Eigen::MatrixXf window = grid.block(i - side, j - side,
01341                                         window_size_pixels, window_size_pixels);
01342                         max = window.maxCoeff();
01343 
01344                         assert(window.cols() == window_size_pixels);
01345                         assert(window.rows() == window_size_pixels);
01346 
01347                         // if max of the window is in its center then this point is local maxima
01348                         if ((max == grid(i, j)) && (max > 0) && (max > threshold)) {
01349                                 local_max(i, j) = 1;
01350                         }
01351                 }
01352         }
01353 
01354         return local_max;
01355 
01356 }
01357 
01358 template<class PointT, class PointNormalT, class FeatureT>
01359 vector<boost::shared_ptr<std::vector<int> > > pcl17::PHVObjectClassifier<PointT,
01360                 PointNormalT, FeatureT>::findVotedSegments(
01361                 typename pcl17::PointCloud<PointT>::Ptr local_maxima_,
01362                 const string & class_name, float window_size) {
01363 
01364         vector<boost::shared_ptr<std::vector<int> > > voted_segments_;
01365 
01366         std::vector<std::set<int> > segment_combinations;
01367 
01368         for (size_t j = 0; j < local_maxima_->points.size(); j++) {
01369                 PointT local_maxima = local_maxima_->points[j];
01370                 std::vector<int> idx;
01371 
01372                 for (size_t i = 0; i < votes_[class_name].points.size(); i++) {
01373 
01374                         bool in_cell_x1 = votes_[class_name].points[i].x
01375                                         > (local_maxima.x - window_size / 2);
01376                         bool in_cell_x2 = votes_[class_name].points[i].x
01377                                         < (local_maxima.x + window_size / 2);
01378                         bool in_cell_y1 = votes_[class_name].points[i].y
01379                                         > (local_maxima.y - window_size / 2);
01380                         bool in_cell_y2 = votes_[class_name].points[i].y
01381                                         < (local_maxima.y + window_size / 2);
01382 
01383                         if (in_cell_x1 && in_cell_x2 && in_cell_y1 && in_cell_y2) {
01384                                 idx.push_back(i);
01385                         }
01386                 }
01387 
01388                 std::set<int> segment_idx;
01389 
01390                 for (size_t i = 0; i < idx.size(); i++) {
01391                         segment_idx.insert(voted_segment_idx_[class_name][idx[i]]);
01392                 }
01393 
01394                 segment_combinations.push_back(segment_idx);
01395 
01396         }
01397 
01398         std::unique(segment_combinations.begin(), segment_combinations.end());
01399 
01400         for (size_t i = 0; i < segment_combinations.size(); i++) {
01401                 //PointNormalCloudPtr cloud(new PointNormalCloud);
01402                 boost::shared_ptr<std::vector<int> > cloud_idx(new std::vector<int>);
01403 
01404                 for (std::set<int>::iterator it = segment_combinations[i].begin();
01405                                 it != segment_combinations[i].end(); it++) {
01406                         //PointNormalCloud segment(*scene_, *segment_indices_[*it]);
01407                         cloud_idx->insert(cloud_idx->begin(),
01408                                         segment_indices_[*it]->begin(),
01409                                         segment_indices_[*it]->end());
01410 
01411                         //*cloud += segment;
01412                 }
01413 
01414                 voted_segments_.push_back(cloud_idx);
01415 
01416         }
01417 
01418         if (debug_) {
01419 
01420                 for (size_t i = 0; i < voted_segments_.size(); i++) {
01421                         PointNormalCloud seg(*scene_, *voted_segments_[i]);
01422                         std::stringstream ss;
01423                         ss << debug_folder_ << class_name << "_segment_" << i << ".pcd";
01424                         std::cerr << "Writing to file " << ss.str() << std::endl;
01425                         pcl17::io::savePCDFileASCII(ss.str(), seg);
01426                 }
01427         }
01428 
01429         return voted_segments_;
01430 
01431 }
01432 
01433 template<class PointT, class PointNormalT, class FeatureT>
01434 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::fitModelsWithRansac(
01435                 vector<boost::shared_ptr<std::vector<int> > > & voted_segments_,
01436                 const string class_name,
01437                 RandomSampleConsensusSimple<PointNormalT> & ransac,
01438                 vector<PointNormalCloudPtr> & result_, vector<float> & scores_) {
01439 
01440         for (size_t i = 0; i < voted_segments_.size(); i++) {
01441 
01442                 ransac.setSceneSegment(voted_segments_[i]);
01443 
01444                 ransac.computeModel();
01445 
01446                 float score = ransac.getBestScore();
01447 
01448                 std::cerr << "Score " << score << std::endl;
01449 
01450                 if (score > ransac_result_threshold_[class_name]) {
01451                         Eigen::VectorXf model_coefs = ransac.getBestModelCoeficients();
01452 
01453                         Eigen::Affine3f transform;
01454                         transform.setIdentity();
01455                         transform.translate(
01456                                         Eigen::Vector3f(model_coefs[0], model_coefs[1], 0));
01457                         transform.rotate(
01458                                         Eigen::AngleAxisf(model_coefs[2],
01459                                                         Eigen::Vector3f(0, 0, 1)));
01460 
01461                         PointNormalCloudPtr full_model_transformed(new PointNormalCloud);
01462                         pcl17::transformPointCloudWithNormals(*ransac.getModel(),
01463                                         *full_model_transformed, transform);
01464 
01465                         result_.push_back(full_model_transformed);
01466                         scores_.push_back(1 - score);
01467 
01468                 }
01469         }
01470 }
01471 
01472 template<class PointT, class PointNormalT, class FeatureT>
01473 void pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::generateVisibilityScore(
01474                 vector<PointNormalCloudPtr> & result_, vector<float> & scores_) {
01475 
01476         pcl17::octree::OctreePointCloudSearch<PointNormalT> octree(
01477                         subsampling_resolution_ * 2.5f);
01478         octree.setInputCloud(scene_);
01479         octree.addPointsFromInputCloud();
01480 
01481         for (size_t i = 0; i < result_.size(); i++) {
01482                 int free = 0, occupied = 0, occluded = 0;
01483                 for (size_t j = 0; j < result_[i]->points.size(); j++) {
01484                         PointNormalT point = result_[i]->points[j];
01485 
01486                         if (octree.isVoxelOccupiedAtPoint(point)) {
01487                                 occupied++;
01488 
01489                                 continue;
01490                         }
01491 
01492                         Eigen::Vector3f sensor_orig = scene_->sensor_origin_.head(3);
01493                         Eigen::Vector3f look_at = point.getVector3fMap() - sensor_orig;
01494 
01495                         std::vector<int> indices;
01496                         octree.getIntersectedVoxelIndices(sensor_orig, look_at, indices);
01497 
01498                         bool is_occluded = false;
01499                         if (indices.size() > 0) {
01500                                 for (size_t k = 0; k < indices.size(); k++) {
01501                                         Eigen::Vector3f ray =
01502                                                         scene_->points[indices[k]].getVector3fMap()
01503                                                                         - sensor_orig;
01504 
01505                                         if (ray.norm() < look_at.norm()) {
01506                                                 is_occluded = true;
01507                                         }
01508 
01509                                 }
01510                         }
01511 
01512                         if (is_occluded) {
01513                                 occluded++;
01514                                 continue;
01515                         }
01516 
01517                         free++;
01518 
01519                 }
01520 
01521                 scores_[i] = 1
01522                                 - ((float) 2 * occupied + occluded)
01523                                                 / (2 * occupied + occluded + free);
01524                 //std::cerr << "Score " << occupied << " " << occluded << " " << free << " " << score[i] << std::endl;
01525 
01526         }
01527 
01528 }
01529 
01530 template<class PointT, class PointNormalT, class FeatureT>
01531 bool pcl17::PHVObjectClassifier<PointT, PointNormalT, FeatureT>::intersectXY(
01532                 const pcl17::PointCloud<PointNormalT> & cloud1,
01533                 const pcl17::PointCloud<PointNormalT> & cloud2) {
01534 
01535         PointNormalT min1, max1, min2, max2;
01536         pcl17::getMinMax3D<PointNormalT>(cloud1, min1, max1);
01537         pcl17::getMinMax3D<PointNormalT>(cloud2, min2, max2);
01538 
01539         bool intersectX, intersectY;
01540         if (min1.x < min2.x)
01541                 intersectX = max1.x > min2.x;
01542         else if (min1.x > min2.x)
01543                 intersectX = max2.x > min1.x;
01544         else
01545                 // min1.x == min2.x
01546                 intersectX = true;
01547 
01548         if (min1.y < min2.y)
01549                 intersectY = max1.y > min2.y;
01550         else if (min1.y > min2.y)
01551                 intersectY = max2.y > min1.y;
01552         else
01553                 // min1.y == min2.y
01554                 intersectY = true;
01555 
01556         return intersectX && intersectY;
01557 
01558 }
01559 
01560 template<class PointT, class PointNormalT, class FeatureT>
01561 vector<typename pcl17::PointCloud<PointNormalT>::Ptr> pcl17::PHVObjectClassifier<
01562                 PointT, PointNormalT, FeatureT>::removeIntersecting(
01563                 vector<typename pcl17::PointCloud<PointNormalT>::Ptr> & result_,
01564                 vector<float> & scores_, vector<float> * selected_scores) {
01565 
01566         vector<PointNormalCloudPtr> no_intersect_result;
01567 
01568         if (result_.size() == 0)
01569                 return no_intersect_result;
01570 
01571         for (size_t i = 0; i < result_.size(); i++) {
01572                 bool best = true;
01573                 for (size_t j = 0; j < result_.size(); j++) {
01574                         if (intersectXY(*result_[i], *result_[j])) {
01575                                 if (scores_[i] > scores_[j])
01576                                         best = false;
01577                         }
01578 
01579                 }
01580                 if (best) {
01581                         if (selected_scores) {
01582                                 selected_scores->push_back(scores_[i]);
01583                         }
01584                         no_intersect_result.push_back(result_[i]);
01585                 }
01586         }
01587 
01588         return no_intersect_result;
01589 
01590 }
01591 
01592 #endif /* PHVOBJECTCLASSIFIER_HPP_ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


furniture_classification
Author(s): Vladyslav Usenko
autogenerated on Thu May 23 2013 18:32:29