/* * Software License Agreement (BSD License) * * Point Cloud Library (PCL) - www.pointclouds.org * Copyright (c) 2012 Aitor Aldoma, Federico Tombari * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef PCL_RECOGNITION_IMPL_HV_GO_HPP_ #define PCL_RECOGNITION_IMPL_HV_GO_HPP_ #include #include // for getMinMax3D #include #include #include #include template inline void extractEuclideanClustersSmooth(const typename pcl::PointCloud &cloud, const typename pcl::PointCloud &normals, float tolerance, const typename pcl::search::Search::Ptr &tree, std::vector &clusters, double eps_angle, float curvature_threshold, unsigned int min_pts_per_cluster, unsigned int max_pts_per_cluster = (std::numeric_limits::max) ()) { if (tree->getInputCloud ()->size () != cloud.size ()) { PCL_ERROR("[pcl::extractEuclideanClusters] Tree built for a different point cloud dataset\n"); return; } if (cloud.size () != normals.size ()) { PCL_ERROR("[pcl::extractEuclideanClusters] Number of points in the input point cloud different than normals!\n"); return; } // Create a bool vector of processed point indices, and initialize it to false std::vector processed (cloud.size (), false); pcl::Indices nn_indices; std::vector nn_distances; // Process all points in the indices vector int size = static_cast (cloud.size ()); for (int i = 0; i < size; ++i) { if (processed[i]) continue; std::vector seed_queue; int sq_idx = 0; seed_queue.push_back (i); processed[i] = true; while (sq_idx < static_cast (seed_queue.size ())) { if (normals[seed_queue[sq_idx]].curvature > curvature_threshold) { sq_idx++; continue; } // Search for sq_idx if (!tree->radiusSearch (seed_queue[sq_idx], tolerance, nn_indices, nn_distances)) { sq_idx++; continue; } for (std::size_t j = 1; j < nn_indices.size (); ++j) // nn_indices[0] should be sq_idx { if (processed[nn_indices[j]]) // Has this point been processed before ? continue; if (normals[nn_indices[j]].curvature > curvature_threshold) { continue; } //processed[nn_indices[j]] = true; // [-1;1] double dot_p = normals[seed_queue[sq_idx]].normal[0] * normals[nn_indices[j]].normal[0] + normals[seed_queue[sq_idx]].normal[1] * normals[nn_indices[j]].normal[1] + normals[seed_queue[sq_idx]].normal[2] * normals[nn_indices[j]].normal[2]; if (std::abs (std::acos (dot_p)) < eps_angle) { processed[nn_indices[j]] = true; seed_queue.push_back (nn_indices[j]); } } sq_idx++; } // If this queue is satisfactory, add to the clusters if (seed_queue.size () >= min_pts_per_cluster && seed_queue.size () <= max_pts_per_cluster) { pcl::PointIndices r; r.indices.resize (seed_queue.size ()); for (std::size_t j = 0; j < seed_queue.size (); ++j) r.indices[j] = seed_queue[j]; std::sort (r.indices.begin (), r.indices.end ()); r.indices.erase (std::unique (r.indices.begin (), r.indices.end ()), r.indices.end ()); r.header = cloud.header; clusters.push_back (r); // We could avoid a copy by working directly in the vector } } } template mets::gol_type pcl::GlobalHypothesesVerification::evaluateSolution(const std::vector & active, int changed) { float sign = 1.f; //update explained_by_RM if (active[changed]) { //it has been activated updateExplainedVector (recognition_models_[changed]->explained_, recognition_models_[changed]->explained_distances_, explained_by_RM_, explained_by_RM_distance_weighted, 1.f); updateUnexplainedVector (recognition_models_[changed]->unexplained_in_neighborhood, recognition_models_[changed]->unexplained_in_neighborhood_weights, unexplained_by_RM_neighboorhods, recognition_models_[changed]->explained_, explained_by_RM_, 1.f); updateCMDuplicity(recognition_models_[changed]->complete_cloud_occupancy_indices_, complete_cloud_occupancy_by_RM_, 1.f); } else { //it has been deactivated updateExplainedVector (recognition_models_[changed]->explained_, recognition_models_[changed]->explained_distances_, explained_by_RM_, explained_by_RM_distance_weighted, -1.f); updateUnexplainedVector (recognition_models_[changed]->unexplained_in_neighborhood, recognition_models_[changed]->unexplained_in_neighborhood_weights, unexplained_by_RM_neighboorhods, recognition_models_[changed]->explained_, explained_by_RM_, -1.f); updateCMDuplicity(recognition_models_[changed]->complete_cloud_occupancy_indices_, complete_cloud_occupancy_by_RM_, -1.f); sign = -1.f; } int duplicity = getDuplicity (); float good_info = getExplainedValue (); float unexplained_info = getPreviousUnexplainedValue (); float bad_info = static_cast (getPreviousBadInfo ()) + (recognition_models_[changed]->outliers_weight_ * static_cast (recognition_models_[changed]->bad_information_)) * sign; setPreviousBadInfo (bad_info); int n_active_hyp = 0; for(const bool i : active) { if(i) n_active_hyp++; } float duplicity_cm = static_cast (getDuplicityCM ()) * w_occupied_multiple_cm_; return static_cast ((good_info - bad_info - static_cast (duplicity) - unexplained_info - duplicity_cm - static_cast (n_active_hyp)) * -1.f); //return the dual to our max problem } /////////////////////////////////////////////////////////////////////////////////////////////////// template void pcl::GlobalHypothesesVerification::initialize() { //clear stuff recognition_models_.clear (); unexplained_by_RM_neighboorhods.clear (); explained_by_RM_distance_weighted.clear (); explained_by_RM_.clear (); mask_.clear (); indices_.clear (), complete_cloud_occupancy_by_RM_.clear (); // initialize mask to false mask_.resize (complete_models_.size ()); for (std::size_t i = 0; i < complete_models_.size (); i++) mask_[i] = false; indices_.resize (complete_models_.size ()); NormalEstimator_ n3d; scene_normals_.reset (new pcl::PointCloud ()); typename pcl::search::KdTree::Ptr normals_tree (new pcl::search::KdTree); normals_tree->setInputCloud (scene_cloud_downsampled_); n3d.setRadiusSearch (radius_normals_); n3d.setSearchMethod (normals_tree); n3d.setInputCloud (scene_cloud_downsampled_); n3d.compute (*scene_normals_); //check nans... int j = 0; for (std::size_t i = 0; i < scene_normals_->size (); ++i) { if (!std::isfinite ((*scene_normals_)[i].normal_x) || !std::isfinite ((*scene_normals_)[i].normal_y) || !std::isfinite ((*scene_normals_)[i].normal_z)) continue; (*scene_normals_)[j] = (*scene_normals_)[i]; (*scene_cloud_downsampled_)[j] = (*scene_cloud_downsampled_)[i]; j++; } scene_normals_->points.resize (j); scene_normals_->width = j; scene_normals_->height = 1; scene_cloud_downsampled_->points.resize (j); scene_cloud_downsampled_->width = j; scene_cloud_downsampled_->height = 1; explained_by_RM_.resize (scene_cloud_downsampled_->size (), 0); explained_by_RM_distance_weighted.resize (scene_cloud_downsampled_->size (), 0.f); unexplained_by_RM_neighboorhods.resize (scene_cloud_downsampled_->size (), 0.f); //compute segmentation of the scene if detect_clutter_ if (detect_clutter_) { //initialize kdtree for search scene_downsampled_tree_.reset (new pcl::search::KdTree); scene_downsampled_tree_->setInputCloud (scene_cloud_downsampled_); std::vector clusters; double eps_angle_threshold = 0.2; int min_points = 20; float curvature_threshold = 0.045f; extractEuclideanClustersSmooth (*scene_cloud_downsampled_, *scene_normals_, inliers_threshold_ * 2.f, scene_downsampled_tree_, clusters, eps_angle_threshold, curvature_threshold, min_points); clusters_cloud_.reset (new pcl::PointCloud); clusters_cloud_->points.resize (scene_cloud_downsampled_->size ()); clusters_cloud_->width = scene_cloud_downsampled_->width; clusters_cloud_->height = 1; for (std::size_t i = 0; i < scene_cloud_downsampled_->size (); i++) { pcl::PointXYZI p; p.getVector3fMap () = (*scene_cloud_downsampled_)[i].getVector3fMap (); p.intensity = 0.f; (*clusters_cloud_)[i] = p; } float intens_incr = 100.f / static_cast (clusters.size ()); float intens = intens_incr; for (const auto &cluster : clusters) { for (const auto &vertex : cluster.indices) { (*clusters_cloud_)[vertex].intensity = intens; } intens += intens_incr; } } //compute cues { pcl::ScopeTime tcues ("Computing cues"); recognition_models_.resize (complete_models_.size ()); int valid = 0; for (int i = 0; i < static_cast (complete_models_.size ()); i++) { //create recognition model recognition_models_[valid].reset (new RecognitionModel ()); if(addModel (visible_models_[i], complete_models_[i], recognition_models_[valid])) { indices_[valid] = i; valid++; } } recognition_models_.resize(valid); indices_.resize(valid); } //compute the bounding boxes for the models ModelT min_pt_all, max_pt_all; min_pt_all.x = min_pt_all.y = min_pt_all.z = std::numeric_limits::max (); max_pt_all.x = max_pt_all.y = max_pt_all.z = (std::numeric_limits::max () - 0.001f) * -1; for (std::size_t i = 0; i < recognition_models_.size (); i++) { ModelT min_pt, max_pt; pcl::getMinMax3D (*complete_models_[indices_[i]], min_pt, max_pt); if (min_pt.x < min_pt_all.x) min_pt_all.x = min_pt.x; if (min_pt.y < min_pt_all.y) min_pt_all.y = min_pt.y; if (min_pt.z < min_pt_all.z) min_pt_all.z = min_pt.z; if (max_pt.x > max_pt_all.x) max_pt_all.x = max_pt.x; if (max_pt.y > max_pt_all.y) max_pt_all.y = max_pt.y; if (max_pt.z > max_pt_all.z) max_pt_all.z = max_pt.z; } int size_x, size_y, size_z; size_x = static_cast (std::ceil (std::abs (max_pt_all.x - min_pt_all.x) / res_occupancy_grid_)) + 1; size_y = static_cast (std::ceil (std::abs (max_pt_all.y - min_pt_all.y) / res_occupancy_grid_)) + 1; size_z = static_cast (std::ceil (std::abs (max_pt_all.z - min_pt_all.z) / res_occupancy_grid_)) + 1; complete_cloud_occupancy_by_RM_.resize (size_x * size_y * size_z, 0); for (std::size_t i = 0; i < recognition_models_.size (); i++) { std::map banned; std::map::iterator banned_it; for (const auto& point: *complete_models_[indices_[i]]) { const int pos_x = static_cast (std::floor ((point.x - min_pt_all.x) / res_occupancy_grid_)); const int pos_y = static_cast (std::floor ((point.y - min_pt_all.y) / res_occupancy_grid_)); const int pos_z = static_cast (std::floor ((point.z - min_pt_all.z) / res_occupancy_grid_)); const int idx = pos_z * size_x * size_y + pos_y * size_x + pos_x; banned_it = banned.find (idx); if (banned_it == banned.end ()) { complete_cloud_occupancy_by_RM_[idx]++; recognition_models_[i]->complete_cloud_occupancy_indices_.push_back (idx); banned[idx] = true; } } } { pcl::ScopeTime tcues ("Computing clutter cues"); #pragma omp parallel for \ default(none) \ schedule(dynamic, 4) \ num_threads(omp_get_num_procs()) for (int j = 0; j < static_cast (recognition_models_.size ()); j++) computeClutterCue (recognition_models_[j]); } cc_.clear (); n_cc_ = 1; cc_.resize (n_cc_); for (std::size_t i = 0; i < recognition_models_.size (); i++) cc_[0].push_back (static_cast (i)); } template void pcl::GlobalHypothesesVerification::SAOptimize(std::vector & cc_indices, std::vector & initial_solution) { //temporal copy of recogniton_models_ std::vector recognition_models_copy; recognition_models_copy = recognition_models_; recognition_models_.clear (); for (const int &cc_index : cc_indices) { recognition_models_.push_back (recognition_models_copy[cc_index]); } for (std::size_t j = 0; j < recognition_models_.size (); j++) { RecognitionModelPtr recog_model = recognition_models_[j]; for (std::size_t i = 0; i < recog_model->explained_.size (); i++) { explained_by_RM_[recog_model->explained_[i]]++; explained_by_RM_distance_weighted[recog_model->explained_[i]] += recog_model->explained_distances_[i]; } if (detect_clutter_) { for (std::size_t i = 0; i < recog_model->unexplained_in_neighborhood.size (); i++) { unexplained_by_RM_neighboorhods[recog_model->unexplained_in_neighborhood[i]] += recog_model->unexplained_in_neighborhood_weights[i]; } } } int occupied_multiple = 0; for(std::size_t i=0; i < complete_cloud_occupancy_by_RM_.size(); i++) { if(complete_cloud_occupancy_by_RM_[i] > 1) { occupied_multiple+=complete_cloud_occupancy_by_RM_[i]; } } setPreviousDuplicityCM(occupied_multiple); //do optimization //Define model SAModel, initial solution is all models activated int duplicity; float good_information_ = getTotalExplainedInformation (explained_by_RM_, explained_by_RM_distance_weighted, &duplicity); float bad_information_ = 0; float unexplained_in_neighboorhod = getUnexplainedInformationInNeighborhood (unexplained_by_RM_neighboorhods, explained_by_RM_); for (std::size_t i = 0; i < initial_solution.size (); i++) { if (initial_solution[i]) bad_information_ += recognition_models_[i]->outliers_weight_ * static_cast (recognition_models_[i]->bad_information_); } setPreviousExplainedValue (good_information_); setPreviousDuplicity (duplicity); setPreviousBadInfo (bad_information_); setPreviousUnexplainedValue (unexplained_in_neighboorhod); SAModel model; model.cost_ = static_cast ((good_information_ - bad_information_ - static_cast (duplicity) - static_cast (occupied_multiple) * w_occupied_multiple_cm_ - static_cast (recognition_models_.size ()) - unexplained_in_neighboorhod) * -1.f); model.setSolution (initial_solution); model.setOptimizer (this); SAModel best (model); move_manager neigh (static_cast (cc_indices.size ())); mets::best_ever_solution best_recorder (best); mets::noimprove_termination_criteria noimprove (max_iterations_); mets::linear_cooling linear_cooling; mets::simulated_annealing sa (model, best_recorder, neigh, noimprove, linear_cooling, initial_temp_, 1e-7, 2); sa.setApplyAndEvaluate(true); { pcl::ScopeTime t ("SA search..."); sa.search (); } best_seen_ = static_cast (best_recorder.best_seen ()); for (std::size_t i = 0; i < best_seen_.solution_.size (); i++) { initial_solution[i] = best_seen_.solution_[i]; } recognition_models_ = recognition_models_copy; } /////////////////////////////////////////////////////////////////////////////////////////////////// template void pcl::GlobalHypothesesVerification::verify() { initialize (); //for each connected component, find the optimal solution for (int c = 0; c < n_cc_; c++) { //TODO: Check for trivial case... //TODO: Check also the number of hypotheses and use exhaustive enumeration if smaller than 10 std::vector subsolution (cc_[c].size (), true); SAOptimize (cc_[c], subsolution); for (std::size_t i = 0; i < subsolution.size (); i++) { mask_[indices_[cc_[c][i]]] = (subsolution[i]); } } } template bool pcl::GlobalHypothesesVerification::addModel(typename pcl::PointCloud::ConstPtr & model, typename pcl::PointCloud::ConstPtr & complete_model, RecognitionModelPtr & recog_model) { //voxelize model cloud recog_model->cloud_.reset (new pcl::PointCloud ()); recog_model->complete_cloud_.reset (new pcl::PointCloud ()); float size_model = resolution_; pcl::VoxelGrid voxel_grid; voxel_grid.setInputCloud (model); voxel_grid.setLeafSize (size_model, size_model, size_model); voxel_grid.filter (*(recog_model->cloud_)); pcl::VoxelGrid voxel_grid2; voxel_grid2.setInputCloud (complete_model); voxel_grid2.setLeafSize (size_model, size_model, size_model); voxel_grid2.filter (*(recog_model->complete_cloud_)); { //check nans... int j = 0; for (auto& point: *(recog_model->cloud_)) { if (!isXYZFinite (point)) continue; (*recog_model->cloud_)[j] = point; j++; } recog_model->cloud_->points.resize (j); recog_model->cloud_->width = j; recog_model->cloud_->height = 1; } if (recog_model->cloud_->points.empty ()) { PCL_WARN("The model cloud has no points..\n"); return false; } //compute normals unless given (now do it always...) typename pcl::search::KdTree::Ptr normals_tree (new pcl::search::KdTree); pcl::NormalEstimation n3d; recog_model->normals_.reset (new pcl::PointCloud ()); normals_tree->setInputCloud (recog_model->cloud_); n3d.setRadiusSearch (radius_normals_); n3d.setSearchMethod (normals_tree); n3d.setInputCloud ((recog_model->cloud_)); n3d.compute (*(recog_model->normals_)); //check nans... int j = 0; for (std::size_t i = 0; i < recog_model->normals_->size (); ++i) { if (isNormalFinite((*recog_model->normals_)[i])) continue; (*recog_model->normals_)[j] = (*recog_model->normals_)[i]; (*recog_model->cloud_)[j] = (*recog_model->cloud_)[i]; j++; } recog_model->normals_->points.resize (j); recog_model->normals_->width = j; recog_model->normals_->height = 1; recog_model->cloud_->points.resize (j); recog_model->cloud_->width = j; recog_model->cloud_->height = 1; std::vector explained_indices; std::vector outliers_weight; std::vector explained_indices_distances; pcl::Indices nn_indices; std::vector nn_distances; std::map>>> model_explains_scene_points; //which point i from the scene is explained by a points j_k with dist d_k from the model outliers_weight.resize (recog_model->cloud_->size ()); recog_model->outlier_indices_.resize (recog_model->cloud_->size ()); std::size_t o = 0; for (std::size_t i = 0; i < recog_model->cloud_->size (); i++) { if (!scene_downsampled_tree_->radiusSearch ((*recog_model->cloud_)[i], inliers_threshold_, nn_indices, nn_distances, std::numeric_limits::max ())) { //outlier outliers_weight[o] = regularizer_; recog_model->outlier_indices_[o] = static_cast (i); o++; } else { for (std::size_t k = 0; k < nn_distances.size (); k++) { std::pair pair = std::make_pair (i, nn_distances[k]); //i is a index to a model point and then distance auto it = model_explains_scene_points.find (nn_indices[k]); if (it == model_explains_scene_points.end ()) { std::shared_ptr>> vec (new std::vector> ()); vec->push_back (pair); model_explains_scene_points[nn_indices[k]] = vec; } else { it->second->push_back (pair); } } } } outliers_weight.resize (o); recog_model->outlier_indices_.resize (o); recog_model->outliers_weight_ = (std::accumulate (outliers_weight.begin (), outliers_weight.end (), 0.f) / static_cast (outliers_weight.size ())); if (outliers_weight.empty ()) recog_model->outliers_weight_ = 1.f; pcl::IndicesPtr indices_scene (new pcl::Indices); //go through the map and keep the closest model point in case that several model points explain a scene point int p = 0; for (auto it = model_explains_scene_points.cbegin (); it != model_explains_scene_points.cend (); it++, p++) { std::size_t closest = 0; float min_d = std::numeric_limits::min (); for (std::size_t i = 0; i < it->second->size (); i++) { if (it->second->at (i).second > min_d) { min_d = it->second->at (i).second; closest = i; } } float d = it->second->at (closest).second; float d_weight = -(d * d / (inliers_threshold_)) + 1; //it->first is index to scene point //using normals to weight inliers Eigen::Vector3f scene_p_normal = (*scene_normals_)[it->first].getNormalVector3fMap (); Eigen::Vector3f model_p_normal = (*recog_model->normals_)[it->second->at(closest).first].getNormalVector3fMap(); float dotp = scene_p_normal.dot (model_p_normal) * 1.f; //[-1,1] from antiparallel trough perpendicular to parallel if (dotp < 0.f) dotp = 0.f; explained_indices.push_back (it->first); explained_indices_distances.push_back (d_weight * dotp); } recog_model->bad_information_ = static_cast (recog_model->outlier_indices_.size ()); recog_model->explained_ = explained_indices; recog_model->explained_distances_ = explained_indices_distances; return true; } template void pcl::GlobalHypothesesVerification::computeClutterCue(RecognitionModelPtr & recog_model) { if (detect_clutter_) { float rn_sqr = radius_neighborhood_GO_ * radius_neighborhood_GO_; pcl::Indices nn_indices; std::vector nn_distances; std::vector < std::pair > neighborhood_indices; //first is indices to scene point and second is indices to explained_ scene points for (pcl::index_t i = 0; i < static_cast (recog_model->explained_.size ()); i++) { if (scene_downsampled_tree_->radiusSearch ((*scene_cloud_downsampled_)[recog_model->explained_[i]], radius_neighborhood_GO_, nn_indices, nn_distances, std::numeric_limits::max ())) { for (std::size_t k = 0; k < nn_distances.size (); k++) { if (nn_indices[k] != i) neighborhood_indices.emplace_back (nn_indices[k], i); } } } //sort neighborhood indices by id std::sort (neighborhood_indices.begin (), neighborhood_indices.end (), [] (const auto& p1, const auto& p2) { return p1.first < p2.first; }); //erase duplicated unexplained points neighborhood_indices.erase ( std::unique (neighborhood_indices.begin (), neighborhood_indices.end (), [] (const auto& p1, const auto& p2) { return p1.first == p2.first; }), neighborhood_indices.end ()); //sort explained points std::vector exp_idces (recog_model->explained_); std::sort (exp_idces.begin (), exp_idces.end ()); recog_model->unexplained_in_neighborhood.resize (neighborhood_indices.size ()); recog_model->unexplained_in_neighborhood_weights.resize (neighborhood_indices.size ()); std::size_t p = 0; std::size_t j = 0; for (const auto &neighborhood_index : neighborhood_indices) { if ((j < exp_idces.size ()) && (neighborhood_index.first == exp_idces[j])) { //this index is explained by the hypothesis so ignore it, advance j j++; } else { //indices_in_nb[i] < exp_idces[j] //recog_model->unexplained_in_neighborhood.push_back(neighborhood_indices[i]); recog_model->unexplained_in_neighborhood[p] = neighborhood_index.first; if ((*clusters_cloud_)[recog_model->explained_[neighborhood_index.second]].intensity != 0.f && ((*clusters_cloud_)[recog_model->explained_[neighborhood_index.second]].intensity == (*clusters_cloud_)[neighborhood_index.first].intensity)) { recog_model->unexplained_in_neighborhood_weights[p] = clutter_regularizer_; } else { //neighborhood_indices[i].first gives the index to the scene point and second to the explained scene point by the model causing this... //calculate weight of this clutter point based on the distance of the scene point and the model point causing it float d = static_cast (pow ( ((*scene_cloud_downsampled_)[recog_model->explained_[neighborhood_index.second]].getVector3fMap () - (*scene_cloud_downsampled_)[neighborhood_index.first].getVector3fMap ()).norm (), 2)); float d_weight = -(d / rn_sqr) + 1; //points that are close have a strong weight*/ //using normals to weight clutter points Eigen::Vector3f scene_p_normal = (*scene_normals_)[neighborhood_index.first].getNormalVector3fMap (); Eigen::Vector3f model_p_normal = (*scene_normals_)[recog_model->explained_[neighborhood_index.second]].getNormalVector3fMap (); float dotp = scene_p_normal.dot (model_p_normal); //[-1,1] from antiparallel trough perpendicular to parallel if (dotp < 0) dotp = 0.f; recog_model->unexplained_in_neighborhood_weights[p] = d_weight * dotp; } p++; } } recog_model->unexplained_in_neighborhood_weights.resize (p); recog_model->unexplained_in_neighborhood.resize (p); } } #define PCL_INSTANTIATE_GoHV(T1,T2) template class PCL_EXPORTS pcl::GlobalHypothesesVerification; #endif /* PCL_RECOGNITION_IMPL_HV_GO_HPP_ */