/* * Software License Agreement (BSD License) * * Point Cloud Library (PCL) - www.pointclouds.org * Copyright (c) 2010-2011, Willow Garage, Inc. * Copyright (c) 2012-, Open Perception, Inc. * * 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 the copyright holder(s) 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. * */ #pragma once #include #include // for computePairFeatures #include // for pcl::isFinite ////////////////////////////////////////////////////////////////////////////////////////////// template bool pcl::PFHEstimation::computePairFeatures ( const pcl::PointCloud &cloud, const pcl::PointCloud &normals, int p_idx, int q_idx, float &f1, float &f2, float &f3, float &f4) { pcl::computePairFeatures (cloud[p_idx].getVector4fMap (), normals[p_idx].getNormalVector4fMap (), cloud[q_idx].getVector4fMap (), normals[q_idx].getNormalVector4fMap (), f1, f2, f3, f4); return (true); } ////////////////////////////////////////////////////////////////////////////////////////////// template void pcl::PFHEstimation::computePointPFHSignature ( const pcl::PointCloud &cloud, const pcl::PointCloud &normals, const pcl::Indices &indices, int nr_split, Eigen::VectorXf &pfh_histogram) { int h_index, h_p; // Clear the resultant point histogram pfh_histogram.setZero (); // Factorization constant float hist_incr = 100.0f / static_cast (indices.size () * (indices.size () - 1) / 2); std::pair key; bool key_found = false; // Iterate over all the points in the neighborhood for (std::size_t i_idx = 0; i_idx < indices.size (); ++i_idx) { for (std::size_t j_idx = 0; j_idx < i_idx; ++j_idx) { // If the 3D points are invalid, don't bother estimating, just continue if (!isFinite (cloud[indices[i_idx]]) || !isFinite (cloud[indices[j_idx]])) continue; if (use_cache_) { // In order to create the key, always use the smaller index as the first key pair member int p1, p2; // if (indices[i_idx] >= indices[j_idx]) // { p1 = indices[i_idx]; p2 = indices[j_idx]; // } // else // { // p1 = indices[j_idx]; // p2 = indices[i_idx]; // } key = std::pair (p1, p2); // Check to see if we already estimated this pair in the global hashmap auto fm_it = feature_map_.find (key); if (fm_it != feature_map_.end ()) { pfh_tuple_ = fm_it->second; key_found = true; } else { // Compute the pair NNi to NNj if (!computePairFeatures (cloud, normals, indices[i_idx], indices[j_idx], pfh_tuple_[0], pfh_tuple_[1], pfh_tuple_[2], pfh_tuple_[3])) continue; key_found = false; } } else if (!computePairFeatures (cloud, normals, indices[i_idx], indices[j_idx], pfh_tuple_[0], pfh_tuple_[1], pfh_tuple_[2], pfh_tuple_[3])) continue; // Normalize the f1, f2, f3 features and push them in the histogram f_index_[0] = static_cast (std::floor (nr_split * ((pfh_tuple_[0] + M_PI) * d_pi_))); if (f_index_[0] < 0) f_index_[0] = 0; if (f_index_[0] >= nr_split) f_index_[0] = nr_split - 1; f_index_[1] = static_cast (std::floor (nr_split * ((pfh_tuple_[1] + 1.0) * 0.5))); if (f_index_[1] < 0) f_index_[1] = 0; if (f_index_[1] >= nr_split) f_index_[1] = nr_split - 1; f_index_[2] = static_cast (std::floor (nr_split * ((pfh_tuple_[2] + 1.0) * 0.5))); if (f_index_[2] < 0) f_index_[2] = 0; if (f_index_[2] >= nr_split) f_index_[2] = nr_split - 1; // Copy into the histogram h_index = 0; h_p = 1; for (const int &d : f_index_) { h_index += h_p * d; h_p *= nr_split; } pfh_histogram[h_index] += hist_incr; if (use_cache_ && !key_found) { // Save the value in the hashmap feature_map_[key] = pfh_tuple_; // Use a maximum cache so that we don't go overboard on RAM usage key_list_.push (key); // Check to see if we need to remove an element due to exceeding max_size if (key_list_.size () > max_cache_size_) { // Remove the oldest element. feature_map_.erase (key_list_.front ()); key_list_.pop (); } } } } } ////////////////////////////////////////////////////////////////////////////////////////////// template void pcl::PFHEstimation::computeFeature (PointCloudOut &output) { // Clear the feature map feature_map_.clear (); std::queue > empty; std::swap (key_list_, empty); pfh_histogram_.setZero (nr_subdiv_ * nr_subdiv_ * nr_subdiv_); // Allocate enough space to hold the results // \note This resize is irrelevant for a radiusSearch (). pcl::Indices nn_indices (k_); std::vector nn_dists (k_); output.is_dense = true; // Save a few cycles by not checking every point for NaN/Inf values if the cloud is set to dense if (input_->is_dense) { // Iterating over the entire index vector for (std::size_t idx = 0; idx < indices_->size (); ++idx) { if (this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0) { for (Eigen::Index d = 0; d < pfh_histogram_.size (); ++d) output[idx].histogram[d] = std::numeric_limits::quiet_NaN (); output.is_dense = false; continue; } // Estimate the PFH signature at each patch computePointPFHSignature (*surface_, *normals_, nn_indices, nr_subdiv_, pfh_histogram_); // Copy into the resultant cloud for (Eigen::Index d = 0; d < pfh_histogram_.size (); ++d) output[idx].histogram[d] = pfh_histogram_[d]; } } else { // Iterating over the entire index vector for (std::size_t idx = 0; idx < indices_->size (); ++idx) { if (!isFinite ((*input_)[(*indices_)[idx]]) || this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0) { for (Eigen::Index d = 0; d < pfh_histogram_.size (); ++d) output[idx].histogram[d] = std::numeric_limits::quiet_NaN (); output.is_dense = false; continue; } // Estimate the PFH signature at each patch computePointPFHSignature (*surface_, *normals_, nn_indices, nr_subdiv_, pfh_histogram_); // Copy into the resultant cloud for (Eigen::Index d = 0; d < pfh_histogram_.size (); ++d) output[idx].histogram[d] = pfh_histogram_[d]; } } } #define PCL_INSTANTIATE_PFHEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::PFHEstimation;