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
00037
00038 #ifndef PCL_SUSAN_IMPL_HPP_
00039 #define PCL_SUSAN_IMPL_HPP_
00040
00041 #include <pcl/keypoints/susan.h>
00042 #include <pcl/features/normal_3d.h>
00043 #include <pcl/features/integral_image_normal.h>
00044
00046 template <typename PointInT, typename PointOutT, typename NormalT, typename IntensityT> void
00047 pcl::SUSANKeypoint<PointInT, PointOutT, NormalT, IntensityT>::setNonMaxSupression (bool nonmax)
00048 {
00049 nonmax_ = nonmax;
00050 }
00051
00053 template <typename PointInT, typename PointOutT, typename NormalT, typename IntensityT> void
00054 pcl::SUSANKeypoint<PointInT, PointOutT, NormalT, IntensityT>::setGeometricValidation (bool validate)
00055 {
00056 geometric_validation_ = validate;
00057 }
00058
00060 template <typename PointInT, typename PointOutT, typename NormalT, typename IntensityT> void
00061 pcl::SUSANKeypoint<PointInT, PointOutT, NormalT, IntensityT>::setRadius (float radius)
00062 {
00063 search_radius_ = radius;
00064 }
00065
00067 template <typename PointInT, typename PointOutT, typename NormalT, typename IntensityT> void
00068 pcl::SUSANKeypoint<PointInT, PointOutT, NormalT, IntensityT>::setDistanceThreshold (float distance_threshold)
00069 {
00070 distance_threshold_ = distance_threshold;
00071 }
00072
00074 template <typename PointInT, typename PointOutT, typename NormalT, typename IntensityT> void
00075 pcl::SUSANKeypoint<PointInT, PointOutT, NormalT, IntensityT>::setAngularThreshold (float angular_threshold)
00076 {
00077 angular_threshold_ = angular_threshold;
00078 }
00079
00081 template <typename PointInT, typename PointOutT, typename NormalT, typename IntensityT> void
00082 pcl::SUSANKeypoint<PointInT, PointOutT, NormalT, IntensityT>::setIntensityThreshold (float intensity_threshold)
00083 {
00084 intensity_threshold_ = intensity_threshold;
00085 }
00086
00088 template <typename PointInT, typename PointOutT, typename NormalT, typename IntensityT> void
00089 pcl::SUSANKeypoint<PointInT, PointOutT, NormalT, IntensityT>::setNormals (const PointCloudNConstPtr &normals)
00090 {
00091 normals_ = normals;
00092 }
00093
00095 template <typename PointInT, typename PointOutT, typename NormalT, typename IntensityT> void
00096 pcl::SUSANKeypoint<PointInT, PointOutT, NormalT, IntensityT>::setSearchSurface (const PointCloudInConstPtr &cloud)
00097 {
00098 surface_ = cloud;
00099 normals_.reset (new pcl::PointCloud<NormalT>);
00100 }
00101
00103 template <typename PointInT, typename PointOutT, typename NormalT, typename IntensityT> void
00104 pcl::SUSANKeypoint<PointInT, PointOutT, NormalT, IntensityT>::setNumberOfThreads (unsigned int nr_threads)
00105 {
00106 threads_ = nr_threads;
00107 }
00108
00109
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00214 template <typename PointInT, typename PointOutT, typename NormalT, typename IntensityT> bool
00215 pcl::SUSANKeypoint<PointInT, PointOutT, NormalT, IntensityT>::initCompute ()
00216 {
00217 if (!Keypoint<PointInT, PointOutT>::initCompute ())
00218 {
00219 PCL_ERROR ("[pcl::%s::initCompute] init failed!\n", name_.c_str ());
00220 return (false);
00221 }
00222
00223 if (normals_->empty ())
00224 {
00225 PointCloudNPtr normals (new PointCloudN ());
00226 normals->reserve (normals->size ());
00227 if (!surface_->isOrganized ())
00228 {
00229 pcl::NormalEstimation<PointInT, NormalT> normal_estimation;
00230 normal_estimation.setInputCloud (surface_);
00231 normal_estimation.setRadiusSearch (search_radius_);
00232 normal_estimation.compute (*normals);
00233 }
00234 else
00235 {
00236 IntegralImageNormalEstimation<PointInT, NormalT> normal_estimation;
00237 normal_estimation.setNormalEstimationMethod (pcl::IntegralImageNormalEstimation<PointInT, NormalT>::SIMPLE_3D_GRADIENT);
00238 normal_estimation.setInputCloud (surface_);
00239 normal_estimation.setNormalSmoothingSize (5.0);
00240 normal_estimation.compute (*normals);
00241 }
00242 normals_ = normals;
00243 }
00244 if (normals_->size () != surface_->size ())
00245 {
00246 PCL_ERROR ("[pcl::%s::initCompute] normals given, but the number of normals does not match the number of input points!\n", name_.c_str ());
00247 return (false);
00248 }
00249 return (true);
00250 }
00251
00253 template <typename PointInT, typename PointOutT, typename NormalT, typename IntensityT> bool
00254 pcl::SUSANKeypoint<PointInT, PointOutT, NormalT, IntensityT>::isWithinNucleusCentroid (const Eigen::Vector3f& nucleus,
00255 const Eigen::Vector3f& centroid,
00256 const Eigen::Vector3f& nc,
00257 const PointInT& point) const
00258 {
00259 Eigen::Vector3f pc = centroid - point.getVector3fMap ();
00260 Eigen::Vector3f pn = nucleus - point.getVector3fMap ();
00261 Eigen::Vector3f pc_cross_nc = pc.cross (nc);
00262 return ((pc_cross_nc.norm () <= tolerance_) && (pc.dot (nc) >= 0) && (pn.dot (nc) <= 0));
00263 }
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00301 template <typename PointInT, typename PointOutT, typename NormalT, typename IntensityT> void
00302 pcl::SUSANKeypoint<PointInT, PointOutT, NormalT, IntensityT>::detectKeypoints (PointCloudOut &output)
00303 {
00304 boost::shared_ptr<pcl::PointCloud<PointOutT> > response (new pcl::PointCloud<PointOutT> ());
00305 response->reserve (surface_->size ());
00306
00307
00308 label_idx_ = pcl::getFieldIndex<PointOutT> (output, "label", out_fields_);
00309
00310 const int input_size = static_cast<int> (input_->size ());
00311
00312
00313
00314 for (int point_index = 0; point_index < input_size; ++point_index)
00315 {
00316 const PointInT& point_in = input_->points [point_index];
00317 const NormalT& normal_in = normals_->points [point_index];
00318 if (!isFinite (point_in) || !isFinite (normal_in))
00319 continue;
00320 else
00321 {
00322 Eigen::Vector3f nucleus = point_in.getVector3fMap ();
00323 Eigen::Vector3f nucleus_normal = normals_->points [point_index].getNormalVector3fMap ();
00324 float nucleus_intensity = intensity_ (point_in);
00325 std::vector<int> nn_indices;
00326 std::vector<float> nn_dists;
00327 tree_->radiusSearch (point_in, search_radius_, nn_indices, nn_dists);
00328 float area = 0;
00329 Eigen::Vector3f centroid = Eigen::Vector3f::Zero ();
00330
00331 std::vector<int> usan; usan.reserve (nn_indices.size () - 1);
00332 for (std::vector<int>::const_iterator index = nn_indices.begin(); index != nn_indices.end(); ++index)
00333 {
00334 if ((*index != point_index) && pcl_isfinite (normals_->points[*index].normal_x))
00335 {
00336
00337 if ((fabs (nucleus_intensity - intensity_ (input_->points[*index])) <= intensity_threshold_) ||
00338 (1 - nucleus_normal.dot (normals_->points[*index].getNormalVector3fMap ()) <= angular_threshold_))
00339 {
00340 ++area;
00341 centroid += input_->points[*index].getVector3fMap ();
00342 usan.push_back (*index);
00343 }
00344 }
00345 }
00346
00347 float geometric_threshold = 0.5f * (static_cast<float> (nn_indices.size () - 1));
00348 if ((area > 0) && (area < geometric_threshold))
00349 {
00350
00351 if (!geometric_validation_)
00352 {
00353 PointOutT point_out;
00354 point_out.getVector3fMap () = point_in.getVector3fMap ();
00355
00356 intensity_out_.set (point_out, geometric_threshold - area);
00357
00358 if (label_idx_ != -1)
00359 {
00360
00361 uint32_t label = static_cast<uint32_t> (point_index);
00362 memcpy (reinterpret_cast<char*> (&point_out) + out_fields_[label_idx_].offset,
00363 &label, sizeof (uint32_t));
00364 }
00365
00366
00367
00368 response->push_back (point_out);
00369 }
00370 else
00371 {
00372 centroid /= area;
00373 Eigen::Vector3f dist = nucleus - centroid;
00374
00375 if (dist.norm () >= distance_threshold_)
00376 {
00377
00378 Eigen::Vector3f nc = centroid - nucleus;
00379
00380 std::vector<int>::const_iterator usan_it = usan.begin ();
00381 for (; usan_it != usan.end (); ++usan_it)
00382 {
00383 if (!isWithinNucleusCentroid (nucleus, centroid, nc, input_->points[*usan_it]))
00384 break;
00385 }
00386
00387 if (usan_it == usan.end ())
00388 {
00389 PointOutT point_out;
00390 point_out.getVector3fMap () = point_in.getVector3fMap ();
00391
00392 intensity_out_.set (point_out, geometric_threshold - area);
00393
00394 if (label_idx_ != -1)
00395 {
00396
00397 uint32_t label = static_cast<uint32_t> (point_index);
00398 memcpy (reinterpret_cast<char*> (&point_out) + out_fields_[label_idx_].offset,
00399 &label, sizeof (uint32_t));
00400 }
00401
00402
00403
00404 response->push_back (point_out);
00405 }
00406 }
00407 }
00408 }
00409 }
00410 }
00411
00412 response->height = 1;
00413 response->width = static_cast<uint32_t> (response->size ());
00414
00415 if (!nonmax_)
00416 output = *response;
00417 else
00418 {
00419 output.points.clear ();
00420 output.points.reserve (response->points.size());
00421
00422
00423
00424
00425 for (int idx = 0; idx < static_cast<int> (response->points.size ()); ++idx)
00426 {
00427 const PointOutT& point_in = response->points [idx];
00428 const NormalT& normal_in = normals_->points [idx];
00429
00430 const float intensity = intensity_out_ (response->points[idx]);
00431 if (!isFinite (point_in) || !isFinite (normal_in) || (intensity == 0))
00432 continue;
00433 std::vector<int> nn_indices;
00434 std::vector<float> nn_dists;
00435 tree_->radiusSearch (idx, search_radius_, nn_indices, nn_dists);
00436 bool is_minima = true;
00437 for (std::vector<int>::const_iterator nn_it = nn_indices.begin(); nn_it != nn_indices.end(); ++nn_it)
00438 {
00439
00440 if (intensity > intensity_out_ (response->points[*nn_it]))
00441 {
00442 is_minima = false;
00443 break;
00444 }
00445 }
00446 if (is_minima)
00447
00448
00449
00450 output.points.push_back (response->points[idx]);
00451 }
00452
00453 output.height = 1;
00454 output.width = static_cast<uint32_t> (output.points.size());
00455 }
00456
00457 output.is_dense = input_->is_dense;
00458 }
00459
00460 #define PCL_INSTANTIATE_SUSAN(T,U,N) template class PCL_EXPORTS pcl::SUSANKeypoint<T,U,N>;
00461 #endif // #ifndef PCL_HARRIS_KEYPOINT_3D_IMPL_H_
00462