|
Point Cloud Library (PCL)
1.4.0
|
00001 /* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Point Cloud Library (PCL) - www.pointclouds.org 00005 * Copyright (c) 2010-2011, Willow Garage, Inc. 00006 * 00007 * All rights reserved. 00008 * 00009 * Redistribution and use in source and binary forms, with or without 00010 * modification, are permitted provided that the following conditions 00011 * are met: 00012 * 00013 * * Redistributions of source code must retain the above copyright 00014 * notice, this list of conditions and the following disclaimer. 00015 * * Redistributions in binary form must reproduce the above 00016 * copyright notice, this list of conditions and the following 00017 * disclaimer in the documentation and/or other materials provided 00018 * with the distribution. 00019 * * Neither the name of Willow Garage, Inc. nor the names of its 00020 * contributors may be used to endorse or promote products derived 00021 * from this software without specific prior written permission. 00022 * 00023 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00024 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00025 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00026 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00027 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00028 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00029 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00030 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00031 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00032 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00033 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00034 * POSSIBILITY OF SUCH DAMAGE. 00035 * 00036 * $Id: fpfh.hpp 3755 2011-12-31 23:45:30Z rusu $ 00037 * 00038 */ 00039 00040 #ifndef PCL_FEATURES_IMPL_FPFH_H_ 00041 #define PCL_FEATURES_IMPL_FPFH_H_ 00042 00043 #include <pcl/features/fpfh.h> 00044 #include <pcl/features/pfh.h> 00045 00047 template <typename PointInT, typename PointNT, typename PointOutT> bool 00048 pcl::FPFHEstimation<PointInT, PointNT, PointOutT>::computePairFeatures ( 00049 const pcl::PointCloud<PointInT> &cloud, const pcl::PointCloud<PointNT> &normals, 00050 int p_idx, int q_idx, float &f1, float &f2, float &f3, float &f4) 00051 { 00052 pcl::computePairFeatures (cloud.points[p_idx].getVector4fMap (), normals.points[p_idx].getNormalVector4fMap (), 00053 cloud.points[q_idx].getVector4fMap (), normals.points[q_idx].getNormalVector4fMap (), 00054 f1, f2, f3, f4); 00055 return (true); 00056 } 00057 00059 template <typename PointInT, typename PointNT, typename PointOutT> 00060 void pcl::FPFHEstimation<PointInT, PointNT, PointOutT>:: 00061 computePointSPFHSignature (const pcl::PointCloud<PointInT> &cloud, const pcl::PointCloud<PointNT> &normals, 00062 int p_idx, int row, const std::vector<int> &indices, 00063 Eigen::MatrixXf &hist_f1, Eigen::MatrixXf &hist_f2, Eigen::MatrixXf &hist_f3) 00064 { 00065 Eigen::Vector4f pfh_tuple; 00066 // Get the number of bins from the histograms size 00067 int nr_bins_f1 = hist_f1.cols (); 00068 int nr_bins_f2 = hist_f2.cols (); 00069 int nr_bins_f3 = hist_f3.cols (); 00070 00071 // Factorization constant 00072 float hist_incr = 100.0 / (float)(indices.size () - 1); 00073 00074 // Iterate over all the points in the neighborhood 00075 for (size_t idx = 0; idx < indices.size (); ++idx) 00076 { 00077 // Avoid unnecessary returns 00078 if (p_idx == indices[idx]) 00079 continue; 00080 00081 // Compute the pair P to NNi 00082 if (!computePairFeatures (cloud, normals, p_idx, indices[idx], pfh_tuple[0], pfh_tuple[1], pfh_tuple[2], pfh_tuple[3])) 00083 continue; 00084 00085 // Normalize the f1, f2, f3 features and push them in the histogram 00086 int h_index = floor (nr_bins_f1 * ((pfh_tuple[0] + M_PI) * d_pi_)); 00087 if (h_index < 0) h_index = 0; 00088 if (h_index >= nr_bins_f1) h_index = nr_bins_f1 - 1; 00089 hist_f1 (row, h_index) += hist_incr; 00090 00091 h_index = floor (nr_bins_f2 * ((pfh_tuple[1] + 1.0) * 0.5)); 00092 if (h_index < 0) h_index = 0; 00093 if (h_index >= nr_bins_f2) h_index = nr_bins_f2 - 1; 00094 hist_f2 (row, h_index) += hist_incr; 00095 00096 h_index = floor (nr_bins_f3 * ((pfh_tuple[2] + 1.0) * 0.5)); 00097 if (h_index < 0) h_index = 0; 00098 if (h_index >= nr_bins_f3) h_index = nr_bins_f3 - 1; 00099 hist_f3 (row, h_index) += hist_incr; 00100 } 00101 } 00102 00104 template <typename PointInT, typename PointNT, typename PointOutT> void 00105 pcl::FPFHEstimation<PointInT, PointNT, PointOutT>::weightPointSPFHSignature ( 00106 const Eigen::MatrixXf &hist_f1, const Eigen::MatrixXf &hist_f2, const Eigen::MatrixXf &hist_f3, 00107 const std::vector<int> &indices, const std::vector<float> &dists, Eigen::VectorXf &fpfh_histogram) 00108 { 00109 assert (indices.size () == dists.size ()); 00110 double sum_f1 = 0.0, sum_f2 = 0.0, sum_f3 = 0.0; 00111 float weight = 0.0, val_f1, val_f2, val_f3; 00112 00113 // Get the number of bins from the histograms size 00114 int nr_bins_f1 = hist_f1.cols (); 00115 int nr_bins_f2 = hist_f2.cols (); 00116 int nr_bins_f3 = hist_f3.cols (); 00117 int nr_bins_f12 = nr_bins_f1 + nr_bins_f2; 00118 00119 // Clear the histogram 00120 fpfh_histogram.setZero (nr_bins_f1 + nr_bins_f2 + nr_bins_f3); 00121 00122 // Use the entire patch 00123 for (size_t idx = 0, data_size = indices.size (); idx < data_size; ++idx) 00124 { 00125 // Minus the query point itself 00126 if (dists[idx] == 0) 00127 continue; 00128 00129 // Standard weighting function used 00130 weight = 1.0 / dists[idx]; 00131 00132 // Weight the SPFH of the query point with the SPFH of its neighbors 00133 for (int f1_i = 0; f1_i < nr_bins_f1; ++f1_i) 00134 { 00135 val_f1 = hist_f1 (indices[idx], f1_i) * weight; 00136 sum_f1 += val_f1; 00137 fpfh_histogram[f1_i] += val_f1; 00138 } 00139 00140 for (int f2_i = 0; f2_i < nr_bins_f2; ++f2_i) 00141 { 00142 val_f2 = hist_f2 (indices[idx], f2_i) * weight; 00143 sum_f2 += val_f2; 00144 fpfh_histogram[f2_i + nr_bins_f1] += val_f2; 00145 } 00146 00147 for (int f3_i = 0; f3_i < nr_bins_f3; ++f3_i) 00148 { 00149 val_f3 = hist_f3 (indices[idx], f3_i) * weight; 00150 sum_f3 += val_f3; 00151 fpfh_histogram[f3_i + nr_bins_f12] += val_f3; 00152 } 00153 } 00154 00155 if (sum_f1 != 0) 00156 sum_f1 = 100.0 / sum_f1; // histogram values sum up to 100 00157 if (sum_f2 != 0) 00158 sum_f2 = 100.0 / sum_f2; // histogram values sum up to 100 00159 if (sum_f3 != 0) 00160 sum_f3 = 100.0 / sum_f3; // histogram values sum up to 100 00161 00162 // Adjust final FPFH values 00163 for (int f1_i = 0; f1_i < nr_bins_f1; ++f1_i) 00164 fpfh_histogram[f1_i] *= sum_f1; 00165 for (int f2_i = 0; f2_i < nr_bins_f2; ++f2_i) 00166 fpfh_histogram[f2_i + nr_bins_f1] *= sum_f2; 00167 for (int f3_i = 0; f3_i < nr_bins_f3; ++f3_i) 00168 fpfh_histogram[f3_i + nr_bins_f12] *= sum_f3; 00169 } 00170 00172 template <typename PointInT, typename PointNT, typename PointOutT> void 00173 pcl::FPFHEstimation<PointInT, PointNT, PointOutT>::computeSPFHSignatures (std::vector<int> &spfh_hist_lookup, 00174 Eigen::MatrixXf &hist_f1, Eigen::MatrixXf &hist_f2, Eigen::MatrixXf &hist_f3) 00175 { 00176 // Allocate enough space to hold the NN search results 00177 // \note This resize is irrelevant for a radiusSearch (). 00178 std::vector<int> nn_indices (k_); 00179 std::vector<float> nn_dists (k_); 00180 00181 std::set<int> spfh_indices; 00182 spfh_hist_lookup.resize (surface_->points.size ()); 00183 00184 // Build a list of (unique) indices for which we will need to compute SPFH signatures 00185 // (We need an SPFH signature for every point that is a neighbor of any point in input_[indices_]) 00186 if (surface_ != input_ || 00187 indices_->size () != surface_->points.size ()) 00188 { 00189 for (size_t idx = 0; idx < indices_->size (); ++idx) 00190 { 00191 int p_idx = (*indices_)[idx]; 00192 this->searchForNeighbors (p_idx, search_parameter_, nn_indices, nn_dists); 00193 00194 spfh_indices.insert (nn_indices.begin (), nn_indices.end ()); 00195 } 00196 } 00197 else 00198 { 00199 // Special case: When a feature must be computed at every point, there is no need for a neighborhood search 00200 for (size_t idx = 0; idx < indices_->size (); ++idx) 00201 spfh_indices.insert ((int) idx); 00202 } 00203 00204 // Initialize the arrays that will store the SPFH signatures 00205 size_t data_size = spfh_indices.size (); 00206 hist_f1.setZero (data_size, nr_bins_f1_); 00207 hist_f2.setZero (data_size, nr_bins_f2_); 00208 hist_f3.setZero (data_size, nr_bins_f3_); 00209 00210 // Compute SPFH signatures for every point that needs them 00211 std::set<int>::iterator spfh_indices_itr = spfh_indices.begin (); 00212 for (size_t i = 0; i < spfh_indices.size (); ++i) 00213 { 00214 // Get the next point index 00215 int p_idx = *spfh_indices_itr; 00216 ++spfh_indices_itr; 00217 00218 // Find the neighborhood around p_idx 00219 this->searchForNeighbors (*surface_, p_idx, search_parameter_, nn_indices, nn_dists); 00220 00221 // Estimate the SPFH signature around p_idx 00222 computePointSPFHSignature (*surface_, *normals_, p_idx, i, nn_indices, hist_f1, hist_f2, hist_f3); 00223 00224 // Populate a lookup table for converting a point index to its corresponding row in the spfh_hist_* matrices 00225 spfh_hist_lookup[p_idx] = i; 00226 } 00227 } 00228 00230 template <typename PointInT, typename PointNT, typename PointOutT> void 00231 pcl::FPFHEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output) 00232 { 00233 // Allocate enough space to hold the NN search results 00234 // \note This resize is irrelevant for a radiusSearch (). 00235 std::vector<int> nn_indices (k_); 00236 std::vector<float> nn_dists (k_); 00237 00238 std::vector<int> spfh_hist_lookup; 00239 computeSPFHSignatures (spfh_hist_lookup, hist_f1_, hist_f2_, hist_f3_); 00240 00241 output.is_dense = true; 00242 // Save a few cycles by not checking every point for NaN/Inf values if the cloud is set to dense 00243 if (input_->is_dense) 00244 { 00245 // Iterate over the entire index vector 00246 for (size_t idx = 0; idx < indices_->size (); ++idx) 00247 { 00248 if (this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0) 00249 { 00250 for (int d = 0; d < fpfh_histogram_.size (); ++d) 00251 output.points[idx].histogram[d] = std::numeric_limits<float>::quiet_NaN (); 00252 00253 output.is_dense = false; 00254 continue; 00255 } 00256 00257 // ... and remap the nn_indices values so that they represent row indices in the spfh_hist_* matrices 00258 // instead of indices into surface_->points 00259 for (size_t i = 0; i < nn_indices.size (); ++i) 00260 nn_indices[i] = spfh_hist_lookup[nn_indices[i]]; 00261 00262 // Compute the FPFH signature (i.e. compute a weighted combination of local SPFH signatures) ... 00263 weightPointSPFHSignature (hist_f1_, hist_f2_, hist_f3_, nn_indices, nn_dists, fpfh_histogram_); 00264 00265 // ...and copy it into the output cloud 00266 for (int d = 0; d < fpfh_histogram_.size (); ++d) 00267 output.points[idx].histogram[d] = fpfh_histogram_[d]; 00268 } 00269 } 00270 else 00271 { 00272 // Iterate over the entire index vector 00273 for (size_t idx = 0; idx < indices_->size (); ++idx) 00274 { 00275 if (!isFinite ((*input_)[(*indices_)[idx]]) || 00276 this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0) 00277 { 00278 for (int d = 0; d < fpfh_histogram_.size (); ++d) 00279 output.points[idx].histogram[d] = std::numeric_limits<float>::quiet_NaN (); 00280 00281 output.is_dense = false; 00282 continue; 00283 } 00284 00285 // ... and remap the nn_indices values so that they represent row indices in the spfh_hist_* matrices 00286 // instead of indices into surface_->points 00287 for (size_t i = 0; i < nn_indices.size (); ++i) 00288 nn_indices[i] = spfh_hist_lookup[nn_indices[i]]; 00289 00290 // Compute the FPFH signature (i.e. compute a weighted combination of local SPFH signatures) ... 00291 weightPointSPFHSignature (hist_f1_, hist_f2_, hist_f3_, nn_indices, nn_dists, fpfh_histogram_); 00292 00293 // ...and copy it into the output cloud 00294 for (int d = 0; d < fpfh_histogram_.size (); ++d) 00295 output.points[idx].histogram[d] = fpfh_histogram_[d]; 00296 } 00297 } 00298 } 00299 00301 template <typename PointInT, typename PointNT> void 00302 pcl::FPFHEstimation<PointInT, PointNT, Eigen::MatrixXf>::computeFeature (pcl::PointCloud<Eigen::MatrixXf> &output) 00303 { 00304 // Allocate enough space to hold the NN search results 00305 // \note This resize is irrelevant for a radiusSearch (). 00306 std::vector<int> nn_indices (k_); 00307 std::vector<float> nn_dists (k_); 00308 00309 std::vector<int> spfh_hist_lookup; 00310 this->computeSPFHSignatures (spfh_hist_lookup, hist_f1_, hist_f2_, hist_f3_); 00311 00312 // Intialize the array that will store the FPFH signature 00313 output.points.resize (indices_->size (), nr_bins_f1_ + nr_bins_f2_ + nr_bins_f3_); 00314 output.is_dense = true; 00315 // Save a few cycles by not checking every point for NaN/Inf values if the cloud is set to dense 00316 if (input_->is_dense) 00317 { 00318 // Iterate over the entire index vector 00319 for (size_t idx = 0; idx < indices_->size (); ++idx) 00320 { 00321 if (!isFinite ((*input_)[(*indices_)[idx]]) || 00322 this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0) 00323 { 00324 output.points.row (idx).setConstant (std::numeric_limits<float>::quiet_NaN ()); 00325 output.is_dense = false; 00326 continue; 00327 } 00328 00329 // ... and remap the nn_indices values so that they represent row indices in the spfh_hist_* matrices 00330 // instead of indices into surface_->points 00331 for (size_t i = 0; i < nn_indices.size (); ++i) 00332 nn_indices[i] = spfh_hist_lookup[nn_indices[i]]; 00333 00334 // Compute the FPFH signature (i.e. compute a weighted combination of local SPFH signatures) ... 00335 this->weightPointSPFHSignature (hist_f1_, hist_f2_, hist_f3_, nn_indices, nn_dists, fpfh_histogram_); 00336 output.points.row (idx) = fpfh_histogram_; 00337 } 00338 } 00339 else 00340 { 00341 // Iterate over the entire index vector 00342 for (size_t idx = 0; idx < indices_->size (); ++idx) 00343 { 00344 if (this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0) 00345 { 00346 output.points.row (idx).setConstant (std::numeric_limits<float>::quiet_NaN ()); 00347 output.is_dense = false; 00348 continue; 00349 } 00350 00351 // ... and remap the nn_indices values so that they represent row indices in the spfh_hist_* matrices 00352 // instead of indices into surface_->points 00353 for (size_t i = 0; i < nn_indices.size (); ++i) 00354 nn_indices[i] = spfh_hist_lookup[nn_indices[i]]; 00355 00356 // Compute the FPFH signature (i.e. compute a weighted combination of local SPFH signatures) ... 00357 this->weightPointSPFHSignature (hist_f1_, hist_f2_, hist_f3_, nn_indices, nn_dists, fpfh_histogram_); 00358 output.points.row (idx) = fpfh_histogram_; 00359 } 00360 } 00361 } 00362 00363 00364 #define PCL_INSTANTIATE_FPFHEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::FPFHEstimation<T,NT,OutT>; 00365 00366 #endif // PCL_FEATURES_IMPL_FPFH_H_ 00367
1.7.6.1