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