00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 template <typename PointInT, typename PointOutT> void
00037 pcl::SIFTKeypoint<PointInT, PointOutT>::setScales (float min_scale, int nr_octaves, int nr_scales_per_octave)
00038 {
00039 if (min_scale <= 0)
00040 {
00041 ROS_ERROR ("[pcl::%s::setScales] : min_scale (%f) must be positive!",
00042 name_.c_str (), min_scale);
00043 return;
00044 }
00045 if (nr_octaves <= 0)
00046 {
00047 ROS_ERROR ("[pcl::%s::setScales] : Number of octaves (%d) must be at least 1!",
00048 name_.c_str (), nr_octaves);
00049 return;
00050 }
00051 if (nr_scales_per_octave < 1)
00052 {
00053 ROS_ERROR ("[pcl::%s::setScales] : Number of scales per octave (%d) must be at least 1!",
00054 name_.c_str (), nr_scales_per_octave);
00055 return;
00056 }
00057 min_scale_ = min_scale;
00058 nr_octaves_ = nr_octaves;
00059 nr_scales_per_octave_ = nr_scales_per_octave;
00060
00061 this->setKSearch (1);
00062 }
00063
00064
00065 template <typename PointInT, typename PointOutT> void
00066 pcl::SIFTKeypoint<PointInT, PointOutT>::setMinimumContrast (float min_contrast)
00067 {
00068 if (min_contrast < 0)
00069 {
00070 ROS_ERROR ("[pcl::%s::setMinimumContrast] : min_contrast (%f) must be non-negative!",
00071 name_.c_str (), min_contrast);
00072 return;
00073 }
00074 min_contrast_ = min_contrast;
00075 }
00076
00077 template <typename PointInT, typename PointOutT> void
00078 pcl::SIFTKeypoint<PointInT, PointOutT>::detectKeypoints (PointCloudOut &output)
00079 {
00080
00081 if (min_scale_ == 0 || nr_octaves_ == 0 || nr_scales_per_octave_ == 0)
00082 {
00083 ROS_ERROR ("[pcl::%s::detectKeypoints] : A valid range of scales must be specified by setScales before detecting keypoints!", name_.c_str ());
00084 return;
00085 }
00086 if (surface_ != input_)
00087 {
00088 ROS_WARN ("[pcl::%s::detectKeypoints] : A search surface has be set by setSearchSurface, but this SIFT keypoint detection algorithm does not support search surfaces other than the input cloud. The cloud provided in setInputCloud is being used instead.", name_.c_str ());
00089 }
00090
00091
00092 output.points.clear ();
00093
00094
00095 boost::shared_ptr<pcl::PointCloud<PointInT> > cloud = input_->makeShared ();
00096
00097
00098 float scale = min_scale_;
00099 for (int i_octave = 0; i_octave < nr_octaves_; ++i_octave)
00100 {
00101
00102 VoxelGrid<PointInT> voxel_grid;
00103 float s = 1.0 * scale;
00104 voxel_grid.setLeafSize (s, s, s);
00105 voxel_grid.setInputCloud (cloud);
00106 voxel_grid.filter (*cloud);
00107
00108
00109 const size_t min_nr_points = 25;
00110 if (cloud->points.size () < min_nr_points)
00111 {
00112 return;
00113 }
00114
00115
00116 tree_->setInputCloud (cloud);
00117
00118
00119 detectKeypointsForOctave (*cloud, *tree_, scale, nr_scales_per_octave_, output);
00120
00121
00122 scale *= 2;
00123 }
00124 }
00125
00126
00127 template <typename PointInT, typename PointOutT> void
00128 pcl::SIFTKeypoint<PointInT, PointOutT>::detectKeypointsForOctave (
00129 const PointCloudIn &input,
00130 KdTree &tree,
00131 float base_scale, int nr_scales_per_octave, PointCloudOut &output)
00132 {
00133
00134 std::vector<float> scales (nr_scales_per_octave + 3);
00135 for (int i_scale = 0; i_scale <= nr_scales_per_octave + 2; ++i_scale)
00136 {
00137 scales[i_scale] = base_scale * pow (2.0, (1.0 * i_scale - 1) / nr_scales_per_octave);
00138 }
00139 Eigen::MatrixXf diff_of_gauss;
00140 computeScaleSpace (input, tree, scales, diff_of_gauss);
00141
00142
00143 std::vector<int> extrema_indices, extrema_scales;
00144 findScaleSpaceExtrema (input, tree, diff_of_gauss, extrema_indices, extrema_scales);
00145
00146
00147 for (size_t i_keypoint = 0; i_keypoint < extrema_indices.size (); ++i_keypoint)
00148 {
00149 PointOutT keypoint;
00150 const int &keypoint_index = extrema_indices[i_keypoint];
00151
00152 keypoint.x = input.points[keypoint_index].x;
00153 keypoint.y = input.points[keypoint_index].y;
00154 keypoint.z = input.points[keypoint_index].z;
00155 keypoint.scale = scales[extrema_scales[i_keypoint]];
00156
00157 output.points.push_back (keypoint);
00158 }
00159 }
00160
00161
00162 template <typename PointInT, typename PointOutT> void
00163 pcl::SIFTKeypoint<PointInT, PointOutT>::computeScaleSpace (
00164 const PointCloudIn &input, KdTree &tree, const std::vector<float> &scales,
00165 Eigen::MatrixXf &diff_of_gauss)
00166 {
00167 std::vector<int> nn_indices;
00168 std::vector<float> nn_dist;
00169 diff_of_gauss.resize (input.size (), scales.size () - 1);
00170
00171
00172 const float max_radius = 3.0 * scales.back ();
00173
00174 for (size_t i_point = 0; i_point < input.size (); ++i_point)
00175 {
00176 tree.radiusSearch (i_point, max_radius, nn_indices, nn_dist);
00177
00178
00179
00180
00181
00182 float filter_response = 0;
00183 float previous_filter_response;
00184 for (size_t i_scale = 0; i_scale < scales.size (); ++i_scale)
00185 {
00186 float sigma_sqr = pow (scales[i_scale], 2);
00187
00188 float numerator = 0.0;
00189 float denominator = 0.0;
00190 for (size_t i_neighbor = 0; i_neighbor < nn_indices.size (); ++i_neighbor)
00191 {
00192 const float &intensity = input.points[nn_indices[i_neighbor]].intensity;
00193 const float &dist_sqr = nn_dist[i_neighbor];
00194 if (dist_sqr <= 9*sigma_sqr)
00195 {
00196 float w = exp (-0.5 * dist_sqr / sigma_sqr);
00197 numerator += intensity * w;
00198 denominator += w;
00199 }
00200 else break;
00201 }
00202 previous_filter_response = filter_response;
00203 filter_response = numerator / denominator;
00204
00205
00206 if (i_scale > 0)
00207 {
00208 diff_of_gauss (i_point, i_scale - 1) = filter_response - previous_filter_response;
00209 }
00210
00211 }
00212 }
00213 }
00214
00215
00216 template <typename PointInT, typename PointOutT> void
00217 pcl::SIFTKeypoint<PointInT, PointOutT>::findScaleSpaceExtrema (
00218 const PointCloudIn &input,
00219 KdTree &tree, const Eigen::MatrixXf &diff_of_gauss,
00220 std::vector<int> &extrema_indices, std::vector<int> &extrema_scales)
00221 {
00222 const int k = 25;
00223 std::vector<int> nn_indices (k);
00224 std::vector<float> nn_dist (k);
00225
00226 float nr_scales = diff_of_gauss.cols ();
00227 std::vector<float> min_val (nr_scales), max_val (nr_scales);
00228
00229 for (size_t i_point = 0; i_point < input.size (); ++i_point)
00230 {
00231
00232 tree.nearestKSearch (i_point, k, nn_indices, nn_dist);
00233
00234
00235
00236
00237
00238 for (int i_scale = 0; i_scale < nr_scales; ++i_scale)
00239 {
00240 min_val[i_scale] = std::numeric_limits<float>::max ();
00241 max_val[i_scale] = -std::numeric_limits<float>::max ();
00242
00243 for (size_t i_neighbor = 0; i_neighbor < nn_indices.size (); ++i_neighbor)
00244 {
00245 const float &d = diff_of_gauss (nn_indices[i_neighbor], i_scale);
00246
00247 min_val[i_scale] = (std::min) (min_val[i_scale], d);
00248 max_val[i_scale] = (std::max) (max_val[i_scale], d);
00249 }
00250 }
00251
00252
00253 for (int i_scale = 1; i_scale < nr_scales - 1; ++i_scale)
00254 {
00255 const float &val = diff_of_gauss (i_point, i_scale);
00256
00257
00258 if (fabs (val) >= min_contrast_)
00259 {
00260
00261 if ((val == min_val[i_scale]) &&
00262 (val < min_val[i_scale - 1]) &&
00263 (val < min_val[i_scale + 1]))
00264 {
00265 extrema_indices.push_back (i_point);
00266 extrema_scales.push_back (i_scale);
00267 }
00268
00269 else if ((val == max_val[i_scale]) &&
00270 (val > max_val[i_scale - 1]) &&
00271 (val > max_val[i_scale + 1]))
00272 {
00273 extrema_indices.push_back (i_point);
00274 extrema_scales.push_back (i_scale);
00275 }
00276 }
00277 }
00278 }
00279 }