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
00039
00040 #ifndef PCL_EXTRACT_CLUSTERS_H_
00041 #define PCL_EXTRACT_CLUSTERS_H_
00042
00043 #include <pcl/pcl_base.h>
00044
00045 #include <pcl/search/pcl_search.h>
00046
00047 namespace pcl
00048 {
00050
00060 template <typename PointT> void
00061 extractEuclideanClusters (
00062 const PointCloud<PointT> &cloud, const boost::shared_ptr<search::Search<PointT> > &tree,
00063 float tolerance, std::vector<PointIndices> &clusters,
00064 unsigned int min_pts_per_cluster = 1, unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ());
00065
00067
00078 template <typename PointT> void
00079 extractEuclideanClusters (
00080 const PointCloud<PointT> &cloud, const std::vector<int> &indices,
00081 const boost::shared_ptr<search::Search<PointT> > &tree, float tolerance, std::vector<PointIndices> &clusters,
00082 unsigned int min_pts_per_cluster = 1, unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ());
00083
00085
00098 template <typename PointT, typename Normal> void
00099 extractEuclideanClusters (
00100 const PointCloud<PointT> &cloud, const PointCloud<Normal> &normals,
00101 float tolerance, const boost::shared_ptr<KdTree<PointT> > &tree,
00102 std::vector<PointIndices> &clusters, double eps_angle,
00103 unsigned int min_pts_per_cluster = 1,
00104 unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ())
00105 {
00106 if (tree->getInputCloud ()->points.size () != cloud.points.size ())
00107 {
00108 PCL_ERROR ("[pcl::extractEuclideanClusters] Tree built for a different point cloud dataset (%zu) than the input cloud (%zu)!\n", tree->getInputCloud ()->points.size (), cloud.points.size ());
00109 return;
00110 }
00111 if (cloud.points.size () != normals.points.size ())
00112 {
00113 PCL_ERROR ("[pcl::extractEuclideanClusters] Number of points in the input point cloud (%zu) different than normals (%zu)!\n", cloud.points.size (), normals.points.size ());
00114 return;
00115 }
00116
00117
00118 std::vector<bool> processed (cloud.points.size (), false);
00119
00120 std::vector<int> nn_indices;
00121 std::vector<float> nn_distances;
00122
00123 for (size_t i = 0; i < cloud.points.size (); ++i)
00124 {
00125 if (processed[i])
00126 continue;
00127
00128 std::vector<unsigned int> seed_queue;
00129 int sq_idx = 0;
00130 seed_queue.push_back (static_cast<int> (i));
00131
00132 processed[i] = true;
00133
00134 while (sq_idx < static_cast<int> (seed_queue.size ()))
00135 {
00136
00137 if (!tree->radiusSearch (seed_queue[sq_idx], tolerance, nn_indices, nn_distances))
00138 {
00139 sq_idx++;
00140 continue;
00141 }
00142
00143 for (size_t j = 1; j < nn_indices.size (); ++j)
00144 {
00145 if (processed[nn_indices[j]])
00146 continue;
00147
00148
00149
00150 double dot_p = normals.points[i].normal[0] * normals.points[nn_indices[j]].normal[0] +
00151 normals.points[i].normal[1] * normals.points[nn_indices[j]].normal[1] +
00152 normals.points[i].normal[2] * normals.points[nn_indices[j]].normal[2];
00153 if ( fabs (acos (dot_p)) < eps_angle )
00154 {
00155 processed[nn_indices[j]] = true;
00156 seed_queue.push_back (nn_indices[j]);
00157 }
00158 }
00159
00160 sq_idx++;
00161 }
00162
00163
00164 if (seed_queue.size () >= min_pts_per_cluster && seed_queue.size () <= max_pts_per_cluster)
00165 {
00166 pcl::PointIndices r;
00167 r.indices.resize (seed_queue.size ());
00168 for (size_t j = 0; j < seed_queue.size (); ++j)
00169 r.indices[j] = seed_queue[j];
00170
00171
00172 std::sort (r.indices.begin (), r.indices.end ());
00173 r.indices.erase (std::unique (r.indices.begin (), r.indices.end ()), r.indices.end ());
00174
00175 r.header = cloud.header;
00176 clusters.push_back (r);
00177 }
00178 }
00179 }
00180
00181
00183
00197 template <typename PointT, typename Normal>
00198 void extractEuclideanClusters (
00199 const PointCloud<PointT> &cloud, const PointCloud<Normal> &normals,
00200 const std::vector<int> &indices, const boost::shared_ptr<KdTree<PointT> > &tree,
00201 float tolerance, std::vector<PointIndices> &clusters, double eps_angle,
00202 unsigned int min_pts_per_cluster = 1,
00203 unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ())
00204 {
00205
00206
00207 if (tree->getInputCloud ()->points.size () != cloud.points.size ())
00208 {
00209 PCL_ERROR ("[pcl::extractEuclideanClusters] Tree built for a different point cloud dataset (%zu) than the input cloud (%zu)!\n", tree->getInputCloud ()->points.size (), cloud.points.size ());
00210 return;
00211 }
00212 if (tree->getIndices ()->size () != indices.size ())
00213 {
00214 PCL_ERROR ("[pcl::extractEuclideanClusters] Tree built for a different set of indices (%zu) than the input set (%zu)!\n", tree->getIndices ()->size (), indices.size ());
00215 return;
00216 }
00217 if (cloud.points.size () != normals.points.size ())
00218 {
00219 PCL_ERROR ("[pcl::extractEuclideanClusters] Number of points in the input point cloud (%zu) different than normals (%zu)!\n", cloud.points.size (), normals.points.size ());
00220 return;
00221 }
00222
00223 std::vector<bool> processed (cloud.points.size (), false);
00224
00225 std::vector<int> nn_indices;
00226 std::vector<float> nn_distances;
00227
00228 for (size_t i = 0; i < indices.size (); ++i)
00229 {
00230 if (processed[indices[i]])
00231 continue;
00232
00233 std::vector<int> seed_queue;
00234 int sq_idx = 0;
00235 seed_queue.push_back (indices[i]);
00236
00237 processed[indices[i]] = true;
00238
00239 while (sq_idx < static_cast<int> (seed_queue.size ()))
00240 {
00241
00242 if (!tree->radiusSearch (cloud.points[seed_queue[sq_idx]], tolerance, nn_indices, nn_distances))
00243 {
00244 sq_idx++;
00245 continue;
00246 }
00247
00248 for (size_t j = 1; j < nn_indices.size (); ++j)
00249 {
00250 if (processed[nn_indices[j]])
00251 continue;
00252
00253
00254
00255 double dot_p =
00256 normals.points[indices[i]].normal[0] * normals.points[indices[nn_indices[j]]].normal[0] +
00257 normals.points[indices[i]].normal[1] * normals.points[indices[nn_indices[j]]].normal[1] +
00258 normals.points[indices[i]].normal[2] * normals.points[indices[nn_indices[j]]].normal[2];
00259 if ( fabs (acos (dot_p)) < eps_angle )
00260 {
00261 processed[nn_indices[j]] = true;
00262 seed_queue.push_back (nn_indices[j]);
00263 }
00264 }
00265
00266 sq_idx++;
00267 }
00268
00269
00270 if (seed_queue.size () >= min_pts_per_cluster && seed_queue.size () <= max_pts_per_cluster)
00271 {
00272 pcl::PointIndices r;
00273 r.indices.resize (seed_queue.size ());
00274 for (size_t j = 0; j < seed_queue.size (); ++j)
00275 r.indices[j] = seed_queue[j];
00276
00277
00278 std::sort (r.indices.begin (), r.indices.end ());
00279 r.indices.erase (std::unique (r.indices.begin (), r.indices.end ()), r.indices.end ());
00280
00281 r.header = cloud.header;
00282 clusters.push_back (r);
00283 }
00284 }
00285 }
00286
00290
00294 template <typename PointT>
00295 class EuclideanClusterExtraction: public PCLBase<PointT>
00296 {
00297 typedef PCLBase<PointT> BasePCLBase;
00298
00299 public:
00300 typedef pcl::PointCloud<PointT> PointCloud;
00301 typedef typename PointCloud::Ptr PointCloudPtr;
00302 typedef typename PointCloud::ConstPtr PointCloudConstPtr;
00303
00304 typedef typename pcl::search::Search<PointT> KdTree;
00305 typedef typename pcl::search::Search<PointT>::Ptr KdTreePtr;
00306
00307 typedef PointIndices::Ptr PointIndicesPtr;
00308 typedef PointIndices::ConstPtr PointIndicesConstPtr;
00309
00311
00312 EuclideanClusterExtraction () : tree_ (),
00313 cluster_tolerance_ (0),
00314 min_pts_per_cluster_ (1),
00315 max_pts_per_cluster_ (std::numeric_limits<int>::max ())
00316 {};
00317
00321 inline void
00322 setSearchMethod (const KdTreePtr &tree)
00323 {
00324 tree_ = tree;
00325 }
00326
00330 inline KdTreePtr
00331 getSearchMethod () const
00332 {
00333 return (tree_);
00334 }
00335
00339 inline void
00340 setClusterTolerance (double tolerance)
00341 {
00342 cluster_tolerance_ = tolerance;
00343 }
00344
00346 inline double
00347 getClusterTolerance () const
00348 {
00349 return (cluster_tolerance_);
00350 }
00351
00355 inline void
00356 setMinClusterSize (int min_cluster_size)
00357 {
00358 min_pts_per_cluster_ = min_cluster_size;
00359 }
00360
00362 inline int
00363 getMinClusterSize () const
00364 {
00365 return (min_pts_per_cluster_);
00366 }
00367
00371 inline void
00372 setMaxClusterSize (int max_cluster_size)
00373 {
00374 max_pts_per_cluster_ = max_cluster_size;
00375 }
00376
00378 inline int
00379 getMaxClusterSize () const
00380 {
00381 return (max_pts_per_cluster_);
00382 }
00383
00387 void
00388 extract (std::vector<PointIndices> &clusters);
00389
00390 protected:
00391
00392 using BasePCLBase::input_;
00393 using BasePCLBase::indices_;
00394 using BasePCLBase::initCompute;
00395 using BasePCLBase::deinitCompute;
00396
00398 KdTreePtr tree_;
00399
00401 double cluster_tolerance_;
00402
00404 int min_pts_per_cluster_;
00405
00407 int max_pts_per_cluster_;
00408
00410 virtual std::string getClassName () const { return ("EuclideanClusterExtraction"); }
00411
00412 };
00413
00417 inline bool
00418 comparePointClusters (const pcl::PointIndices &a, const pcl::PointIndices &b)
00419 {
00420 return (a.indices.size () < b.indices.size ());
00421 }
00422 }
00423
00424 #ifdef PCL_NO_PRECOMPILE
00425 #include <pcl/segmentation/impl/extract_clusters.hpp>
00426 #endif
00427
00428 #endif //#ifndef PCL_EXTRACT_CLUSTERS_H_