00001 
00002 
00003 
00004 
00005 
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         
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         
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                 
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         
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         
00280 
00281         {
00282 
00283                 
00284                 
00285                 
00286                 FeatureT ff;
00287                 
00288 
00289                 std::vector<std::string> st;
00290                 boost::split(st, line, boost::is_any_of(","), boost::token_compress_on);
00291 
00292                 
00293 
00294                 bias.push_back(atof(st[0].c_str()));
00295 
00296                 
00297                 for (size_t i = 0; i < feature_size; i++) {
00298                         
00299                         
00300 
00301                         
00302                         
00303                         
00304                         
00305                         
00306                         
00307                         
00308                         
00309                         ff.histogram[i] = atof(st[i + 1].c_str());
00310                         
00311                 }
00312                 mat.points.push_back(ff);
00313                 mat.width = mat.points.size();
00314                 mat.height = 1;
00315         }
00316 
00317         
00318 
00319         
00320         
00321         
00322         
00323         
00324         
00325         
00326         
00327         
00328         
00329         
00330         
00331         
00332         
00333         
00334         
00335         
00336         
00337         
00338         
00339         
00340         
00341         
00342         
00343 
00344         
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                 
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                 
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                 
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         
00443         boost::shared_ptr<
00444                         pcl17::registration::TransformationEstimationLM<PointNormalT,
00445                                         PointNormalT> > transformEstPointToPlane(
00446                         new pcl17::registration::TransformationEstimationLM<PointNormalT,
00447                                         PointNormalT>());
00448         
00449         icp.setMaximumIterations(icp_max_iterations_);
00450         icp.setMaxCorrespondenceDistance(icp_max_correspondence_distance_);
00451 
00452         icp.setEuclideanFitnessEpsilon(0);
00453 
00454         
00455         icp.setInputTarget(scene_);
00456 
00457         furniture_classification::FittedModelsPtr res(new furniture_classification::FittedModels);
00458         
00459         
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                                 
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                         
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                 
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                 
00622                 
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                 
00684                 
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         
00735         
00736         
00737 
00738         PointNormalCloudPtr cloud_with_normals(new PointNormalCloud);
00739         PointNormalCloudPtr cloud_downsampled(new PointNormalCloud);
00740 
00741         
00742         
00743         
00744         
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         
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         
00775         
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         
00805         region_growing.setSearchMethod(tree);
00806         region_growing.setNumberOfNeighbours(30);
00807         region_growing.setInputCloud(cloud);
00808         
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         
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) { 
00898                 pcl17::PointCloud<FeatureT> feature;
00899                 
00900                 
00901                 feature_estimator_->setIndices(idx);
00902                 feature_estimator_->compute(feature);
00903 
00904                 
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         
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         
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         
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         
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         
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         
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                                 
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         
01080         {
01081 
01082                 
01083                 
01084                 
01085                 FeatureT ff;
01086                 
01087 
01088                 std::vector<std::string> st;
01089                 boost::split(st, line, boost::is_any_of(","), boost::token_compress_on);
01090 
01091                 
01092 
01093                 bias.push_back(atof(st[0].c_str()));
01094 
01095                 
01096                 for (size_t i = 0; i < feature_size; i++) {
01097                         
01098                         
01099 
01100                         
01101                         
01102                         
01103                         
01104                         
01105                         
01106                         
01107                         
01108                         ff.histogram[i] = atof(st[i + 1].c_str());
01109                         
01110                 }
01111                 mat.points.push_back(ff);
01112                 mat.width = mat.points.size();
01113                 mat.height = 1;
01114         }
01115 
01116         
01117         
01118         
01119         
01120         
01121         
01122         
01123         
01124         
01125         
01126         
01127         
01128         
01129         
01130         
01131         
01132         
01133         
01134         
01135         
01136         
01137         
01138         
01139         
01140 
01141         
01142         
01143 
01144         for (size_t i = 0; i < features_.size(); i++) {
01145                 
01146                 
01147                 
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                 
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                 
01179                 
01180 
01181                 
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                         
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                         
01208                         
01209                         
01210                         
01211                         
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         
01265 
01266         
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         
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                         
01284                         
01285                         
01286 
01287                         
01288                         
01289 
01290                         
01291                         if ((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         
01321         float threshold = min + (max - min) * local_maxima_threshold_;
01322         
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         
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                         
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                 
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                         
01407                         cloud_idx->insert(cloud_idx->begin(),
01408                                         segment_indices_[*it]->begin(),
01409                                         segment_indices_[*it]->end());
01410 
01411                         
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                 
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                 
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                 
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