|
Point Cloud Library (PCL)
1.5.1
|
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 */ 00037 00038 #ifndef PCL_SIFT_KEYPOINT_IMPL_H_ 00039 #define PCL_SIFT_KEYPOINT_IMPL_H_ 00040 00041 #include "pcl/keypoints/sift_keypoint.h" 00042 #include <pcl/common/io.h> 00043 #include <pcl/filters/voxel_grid.h> 00044 #include <pcl/filters/approximate_voxel_grid.h> 00045 00047 template <typename PointInT, typename PointOutT> void 00048 pcl::SIFTKeypoint<PointInT, PointOutT>::setScales (float min_scale, int nr_octaves, int nr_scales_per_octave) 00049 { 00050 if (min_scale <= 0) 00051 { 00052 PCL_ERROR ("[pcl::%s::setScales] : min_scale (%f) must be positive!\n", 00053 name_.c_str (), min_scale); 00054 return; 00055 } 00056 if (nr_octaves <= 0) 00057 { 00058 PCL_ERROR ("[pcl::%s::setScales] : Number of octaves (%d) must be at least 1!\n", 00059 name_.c_str (), nr_octaves); 00060 return; 00061 } 00062 if (nr_scales_per_octave < 1) 00063 { 00064 PCL_ERROR ("[pcl::%s::setScales] : Number of scales per octave (%d) must be at least 1!\n", 00065 name_.c_str (), nr_scales_per_octave); 00066 return; 00067 } 00068 min_scale_ = min_scale; 00069 nr_octaves_ = nr_octaves; 00070 nr_scales_per_octave_ = nr_scales_per_octave; 00071 00072 this->setKSearch (1); 00073 } 00074 00075 00077 template <typename PointInT, typename PointOutT> void 00078 pcl::SIFTKeypoint<PointInT, PointOutT>::setMinimumContrast (float min_contrast) 00079 { 00080 if (min_contrast < 0) 00081 { 00082 PCL_ERROR ("[pcl::%s::setMinimumContrast] : min_contrast (%f) must be non-negative!\n", 00083 name_.c_str (), min_contrast); 00084 return; 00085 } 00086 min_contrast_ = min_contrast; 00087 } 00088 00090 template <typename PointInT, typename PointOutT> void 00091 pcl::SIFTKeypoint<PointInT, PointOutT>::detectKeypoints (PointCloudOut &output) 00092 { 00093 tree_.reset (new pcl::search::KdTree<PointInT> (true)); 00094 00095 // Check for valid inputs 00096 if (min_scale_ == 0 || nr_octaves_ == 0 || nr_scales_per_octave_ == 0) 00097 { 00098 PCL_ERROR ("[pcl::%s::detectKeypoints] : ", name_.c_str ()); 00099 PCL_ERROR ("A valid range of scales must be specified by setScales before detecting keypoints!\n"); 00100 return; 00101 } 00102 if (surface_ != input_) 00103 { 00104 PCL_WARN ("[pcl::%s::detectKeypoints] : ", name_.c_str ()); 00105 PCL_WARN ("A search surface has been set by setSearchSurface, but this SIFT keypoint detection algorithm does "); 00106 PCL_WARN ("not support search surfaces other than the input cloud. "); 00107 PCL_WARN ("The cloud provided in setInputCloud is being used instead.\n"); 00108 } 00109 00110 // Check if the output has a "scale" field 00111 scale_idx_ = pcl::getFieldIndex<PointOutT> (output, "scale", out_fields_); 00112 00113 // Make sure the output cloud is empty 00114 output.points.clear (); 00115 00116 // Create a local copy of the input cloud that will be resized for each octave 00117 boost::shared_ptr<pcl::PointCloud<PointInT> > cloud (new pcl::PointCloud<PointInT> (*input_)); 00118 00119 VoxelGrid<PointInT> voxel_grid; 00120 // Search for keypoints at each octave 00121 float scale = min_scale_; 00122 for (int i_octave = 0; i_octave < nr_octaves_; ++i_octave) 00123 { 00124 // Downsample the point cloud 00125 float s = 1.0 * scale; // note: this can be adjusted 00126 voxel_grid.setLeafSize (s, s, s); 00127 voxel_grid.setInputCloud (cloud); 00128 boost::shared_ptr<pcl::PointCloud<PointInT> > temp (new pcl::PointCloud<PointInT>); 00129 voxel_grid.filter (*temp); 00130 cloud = temp; 00131 00132 // Make sure the downsampled cloud still has enough points 00133 const size_t min_nr_points = 25; 00134 if (cloud->points.size () < min_nr_points) 00135 break; 00136 00137 // Update the KdTree with the downsampled points 00138 tree_->setInputCloud (cloud); 00139 00140 // Detect keypoints for the current scale 00141 detectKeypointsForOctave (*cloud, *tree_, scale, nr_scales_per_octave_, output); 00142 00143 // Increase the scale by another octave 00144 scale *= 2; 00145 } 00146 00147 output.height = 1; 00148 output.width = output.points.size (); 00149 } 00150 00151 00153 template <typename PointInT, typename PointOutT> void 00154 pcl::SIFTKeypoint<PointInT, PointOutT>::detectKeypointsForOctave ( 00155 const PointCloudIn &input, KdTree &tree, float base_scale, int nr_scales_per_octave, 00156 PointCloudOut &output) 00157 { 00158 // Compute the difference of Gaussians (DoG) scale space 00159 std::vector<float> scales (nr_scales_per_octave + 3); 00160 for (int i_scale = 0; i_scale <= nr_scales_per_octave + 2; ++i_scale) 00161 { 00162 scales[i_scale] = base_scale * pow (2.0, (1.0 * i_scale - 1) / nr_scales_per_octave); 00163 } 00164 Eigen::MatrixXf diff_of_gauss; 00165 computeScaleSpace (input, tree, scales, diff_of_gauss); 00166 00167 // Find extrema in the DoG scale space 00168 std::vector<int> extrema_indices, extrema_scales; 00169 findScaleSpaceExtrema (input, tree, diff_of_gauss, extrema_indices, extrema_scales); 00170 00171 output.points.reserve (output.points.size () + extrema_indices.size ()); 00172 // Save scale? 00173 if (scale_idx_ != -1) 00174 { 00175 // Add keypoints to output 00176 for (size_t i_keypoint = 0; i_keypoint < extrema_indices.size (); ++i_keypoint) 00177 { 00178 PointOutT keypoint; 00179 const int &keypoint_index = extrema_indices[i_keypoint]; 00180 00181 keypoint.x = input.points[keypoint_index].x; 00182 keypoint.y = input.points[keypoint_index].y; 00183 keypoint.z = input.points[keypoint_index].z; 00184 memcpy (((char*)&keypoint) + out_fields_[scale_idx_].offset, &scales[extrema_scales[i_keypoint]], sizeof (float)); 00185 output.points.push_back (keypoint); 00186 } 00187 } 00188 else 00189 { 00190 // Add keypoints to output 00191 for (size_t i_keypoint = 0; i_keypoint < extrema_indices.size (); ++i_keypoint) 00192 { 00193 PointOutT keypoint; 00194 const int &keypoint_index = extrema_indices[i_keypoint]; 00195 00196 keypoint.x = input.points[keypoint_index].x; 00197 keypoint.y = input.points[keypoint_index].y; 00198 keypoint.z = input.points[keypoint_index].z; 00199 00200 output.points.push_back (keypoint); 00201 } 00202 } 00203 } 00204 00205 00207 template <typename PointInT, typename PointOutT> 00208 void pcl::SIFTKeypoint<PointInT, PointOutT>::computeScaleSpace ( 00209 const PointCloudIn &input, KdTree &tree, const std::vector<float> &scales, 00210 Eigen::MatrixXf &diff_of_gauss) 00211 { 00212 std::vector<int> nn_indices; 00213 std::vector<float> nn_dist; 00214 diff_of_gauss.resize (input.size (), scales.size () - 1); 00215 00216 // For efficiency, we will only filter over points within 3 standard deviations 00217 const float max_radius = 3.0 * scales.back (); 00218 00219 for (size_t i_point = 0; i_point < input.size (); ++i_point) 00220 { 00221 tree.radiusSearch (i_point, max_radius, nn_indices, nn_dist); // * 00222 // * note: at this stage of the algorithm, we must find all points within a radius defined by the maximum scale, 00223 // regardless of the configurable search method specified by the user, so we directly employ tree.radiusSearch 00224 // here instead of using searchForNeighbors. 00225 00226 // For each scale, compute the Gaussian "filter response" at the current point 00227 float filter_response = 0; 00228 float previous_filter_response; 00229 for (size_t i_scale = 0; i_scale < scales.size (); ++i_scale) 00230 { 00231 float sigma_sqr = pow (scales[i_scale], 2); 00232 00233 float numerator = 0.0; 00234 float denominator = 0.0; 00235 for (size_t i_neighbor = 0; i_neighbor < nn_indices.size (); ++i_neighbor) 00236 { 00237 const float &value = getFieldValue_ (input.points[nn_indices[i_neighbor]]); 00238 const float &dist_sqr = nn_dist[i_neighbor]; 00239 if (dist_sqr <= 9*sigma_sqr) 00240 { 00241 float w = exp (-0.5 * dist_sqr / sigma_sqr); 00242 numerator += value * w; 00243 denominator += w; 00244 } 00245 else break; // i.e. if dist > 3 standard deviations, then terminate early 00246 } 00247 previous_filter_response = filter_response; 00248 filter_response = numerator / denominator; 00249 00250 // Compute the difference between adjacent scales 00251 if (i_scale > 0) 00252 diff_of_gauss (i_point, i_scale - 1) = filter_response - previous_filter_response; 00253 } 00254 } 00255 } 00256 00258 template <typename PointInT, typename PointOutT> void 00259 pcl::SIFTKeypoint<PointInT, PointOutT>::findScaleSpaceExtrema ( 00260 const PointCloudIn &input, KdTree &tree, const Eigen::MatrixXf &diff_of_gauss, 00261 std::vector<int> &extrema_indices, std::vector<int> &extrema_scales) 00262 { 00263 const int k = 25; 00264 std::vector<int> nn_indices (k); 00265 std::vector<float> nn_dist (k); 00266 00267 float nr_scales = diff_of_gauss.cols (); 00268 std::vector<float> min_val (nr_scales), max_val (nr_scales); 00269 00270 for (size_t i_point = 0; i_point < input.size (); ++i_point) 00271 { 00272 // Define the local neighborhood around the current point 00273 tree.nearestKSearch (i_point, k, nn_indices, nn_dist); //* 00274 // * note: the neighborhood for finding local extrema is best defined as a small fixed-k neighborhood, regardless of 00275 // the configurable search method specified by the user, so we directly employ tree.nearestKSearch here instead 00276 // of using searchForNeighbors 00277 00278 // At each scale, find the extreme values of the DoG within the current neighborhood 00279 for (int i_scale = 0; i_scale < nr_scales; ++i_scale) 00280 { 00281 min_val[i_scale] = std::numeric_limits<float>::max (); 00282 max_val[i_scale] = -std::numeric_limits<float>::max (); 00283 00284 for (size_t i_neighbor = 0; i_neighbor < nn_indices.size (); ++i_neighbor) 00285 { 00286 const float &d = diff_of_gauss (nn_indices[i_neighbor], i_scale); 00287 00288 min_val[i_scale] = (std::min) (min_val[i_scale], d); 00289 max_val[i_scale] = (std::max) (max_val[i_scale], d); 00290 } 00291 } 00292 00293 // If the current point is an extreme value with high enough contrast, add it as a keypoint 00294 for (int i_scale = 1; i_scale < nr_scales - 1; ++i_scale) 00295 { 00296 const float &val = diff_of_gauss (i_point, i_scale); 00297 00298 // Does the point have sufficient contrast? 00299 if (fabs (val) >= min_contrast_) 00300 { 00301 // Is it a local minimum? 00302 if ((val == min_val[i_scale]) && 00303 (val < min_val[i_scale - 1]) && 00304 (val < min_val[i_scale + 1])) 00305 { 00306 extrema_indices.push_back (i_point); 00307 extrema_scales.push_back (i_scale); 00308 } 00309 // Is it a local maximum? 00310 else if ((val == max_val[i_scale]) && 00311 (val > max_val[i_scale - 1]) && 00312 (val > max_val[i_scale + 1])) 00313 { 00314 extrema_indices.push_back (i_point); 00315 extrema_scales.push_back (i_scale); 00316 } 00317 } 00318 } 00319 } 00320 } 00321 00322 #define PCL_INSTANTIATE_SIFTKeypoint(T,U) template class PCL_EXPORTS pcl::SIFTKeypoint<T,U>; 00323 00324 #endif // #ifndef PCL_SIFT_KEYPOINT_IMPL_H_ 00325
1.8.0