/* * 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. * * $Id$ * */ #ifndef PCL_FEATURES_IMPL_RIFT_H_ #define PCL_FEATURES_IMPL_RIFT_H_ #include ////////////////////////////////////////////////////////////////////////////////////////////// template void pcl::RIFTEstimation::computeRIFT ( const PointCloudIn &cloud, const PointCloudGradient &gradient, int p_idx, float radius, const pcl::Indices &indices, const std::vector &sqr_distances, Eigen::MatrixXf &rift_descriptor) { if (indices.empty ()) { PCL_ERROR ("[pcl::RIFTEstimation] Null indices points passed!\n"); return; } // Determine the number of bins to use based on the size of rift_descriptor int nr_distance_bins = static_cast (rift_descriptor.rows ()); int nr_gradient_bins = static_cast (rift_descriptor.cols ()); // Get the center point pcl::Vector3fMapConst p0 = cloud[p_idx].getVector3fMap (); // Compute the RIFT descriptor rift_descriptor.setZero (); for (std::size_t idx = 0; idx < indices.size (); ++idx) { // Compute the gradient magnitude and orientation (relative to the center point) pcl::Vector3fMapConst point = cloud[indices[idx]].getVector3fMap (); Eigen::Map gradient_vector (& (gradient[indices[idx]].gradient[0])); float gradient_magnitude = gradient_vector.norm (); float gradient_angle_from_center = std::acos (gradient_vector.dot ((point - p0).normalized ()) / gradient_magnitude); if (!std::isfinite (gradient_angle_from_center)) gradient_angle_from_center = 0.0; // Normalize distance and angle values to: 0.0 <= d,g < nr_distances_bins,nr_gradient_bins const float eps = std::numeric_limits::epsilon (); float d = static_cast (nr_distance_bins) * std::sqrt (sqr_distances[idx]) / (radius + eps); float g = static_cast (nr_gradient_bins) * gradient_angle_from_center / (static_cast (M_PI) + eps); // Compute the bin indices that need to be updated int d_idx_min = (std::max)(static_cast (std::ceil (d - 1)), 0); int d_idx_max = (std::min)(static_cast (std::floor (d + 1)), nr_distance_bins - 1); int g_idx_min = static_cast (std::ceil (g - 1)); int g_idx_max = static_cast (std::floor (g + 1)); // Update the appropriate bins of the histogram for (int g_idx = g_idx_min; g_idx <= g_idx_max; ++g_idx) { // Because gradient orientation is cyclical, out-of-bounds values must wrap around int g_idx_wrapped = ((g_idx + nr_gradient_bins) % nr_gradient_bins); for (int d_idx = d_idx_min; d_idx <= d_idx_max; ++d_idx) { // To avoid boundary effects, use linear interpolation when updating each bin float w = (1.0f - std::abs (d - static_cast (d_idx))) * (1.0f - std::abs (g - static_cast (g_idx))); rift_descriptor (d_idx, g_idx_wrapped) += w * gradient_magnitude; } } } // Normalize the RIFT descriptor to unit magnitude rift_descriptor.normalize (); } ////////////////////////////////////////////////////////////////////////////////////////////// template void pcl::RIFTEstimation::computeFeature (PointCloudOut &output) { // Make sure a search radius is set if (search_radius_ == 0.0) { PCL_ERROR ("[pcl::%s::computeFeature] The search radius must be set before computing the feature!\n", getClassName ().c_str ()); output.width = output.height = 0; output.clear (); return; } // Make sure the RIFT descriptor has valid dimensions if (nr_gradient_bins_ <= 0) { PCL_ERROR ("[pcl::%s::computeFeature] The number of gradient bins must be greater than zero!\n", getClassName ().c_str ()); output.width = output.height = 0; output.clear (); return; } if (nr_distance_bins_ <= 0) { PCL_ERROR ("[pcl::%s::computeFeature] The number of distance bins must be greater than zero!\n", getClassName ().c_str ()); output.width = output.height = 0; output.clear (); return; } // Check for valid input gradient if (!gradient_) { PCL_ERROR ("[pcl::%s::computeFeature] No input gradient was given!\n", getClassName ().c_str ()); output.width = output.height = 0; output.clear (); return; } if (gradient_->size () != surface_->size ()) { PCL_ERROR ("[pcl::%s::computeFeature] ", getClassName ().c_str ()); PCL_ERROR ("The number of points in the input dataset differs from the number of points in the gradient!\n"); output.width = output.height = 0; output.clear (); return; } Eigen::MatrixXf rift_descriptor (nr_distance_bins_, nr_gradient_bins_); pcl::Indices nn_indices; std::vector nn_dist_sqr; // Iterating over the entire index vector for (std::size_t idx = 0; idx < indices_->size (); ++idx) { // Find neighbors within the search radius tree_->radiusSearch ((*indices_)[idx], search_radius_, nn_indices, nn_dist_sqr); // Compute the RIFT descriptor computeRIFT (*surface_, *gradient_, (*indices_)[idx], static_cast (search_radius_), nn_indices, nn_dist_sqr, rift_descriptor); // Default layout is column major, copy elementwise std::copy_n (rift_descriptor.data (), rift_descriptor.size (), output[idx].histogram); } } #define PCL_INSTANTIATE_RIFTEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::RIFTEstimation; #endif // PCL_FEATURES_IMPL_RIFT_H_