Point Cloud Library (PCL) 1.15.1-dev
Loading...
Searching...
No Matches
extract_clusters.h
1/*
2 * Software License Agreement (BSD License)
3 *
4 * Point Cloud Library (PCL) - www.pointclouds.org
5 * Copyright (c) 2010-2011, Willow Garage, Inc.
6 *
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided
18 * with the distribution.
19 * * Neither the name of the copyright holder(s) nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *
36 * $Id$
37 *
38 */
39
40#pragma once
41
42#include <pcl/console/print.h> // for PCL_ERROR
43#include <pcl/pcl_base.h>
44
45#include <pcl/search/search.h> // for Search
46#if PCL_HAS_FLANN
47#include <pcl/kdtree/kdtree.h>
48#endif
49
50namespace pcl
51{
52 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
53 /** \brief Decompose a region of space into clusters based on the Euclidean distance between points
54 * \param cloud the point cloud message
55 * \param tree the spatial locator (e.g., kd-tree) used for nearest neighbors searching
56 * \note the tree has to be created as a spatial locator on \a cloud
57 * \param tolerance the spatial cluster tolerance as a measure in L2 Euclidean space
58 * \param clusters the resultant clusters containing point indices (as a vector of PointIndices)
59 * \param min_pts_per_cluster minimum number of points that a cluster may contain (default: 1)
60 * \param max_pts_per_cluster maximum number of points that a cluster may contain (default: max int)
61 * \ingroup segmentation
62 */
63 template <typename PointT> void
65 const PointCloud<PointT> &cloud, const typename search::Search<PointT>::Ptr &tree,
66 float tolerance, std::vector<PointIndices> &clusters,
67 unsigned int min_pts_per_cluster = 1, unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ());
68
69 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
70 /** \brief Decompose a region of space into clusters based on the Euclidean distance between points
71 * \param cloud the point cloud message
72 * \param indices a list of point indices to use from \a cloud
73 * \param tree the spatial locator (e.g., kd-tree) used for nearest neighbors searching
74 * \note the tree has to be created as a spatial locator on \a cloud and \a indices
75 * \param tolerance the spatial cluster tolerance as a measure in L2 Euclidean space
76 * \param clusters the resultant clusters containing point indices (as a vector of PointIndices)
77 * \param min_pts_per_cluster minimum number of points that a cluster may contain (default: 1)
78 * \param max_pts_per_cluster maximum number of points that a cluster may contain (default: max int)
79 * \ingroup segmentation
80 */
81 template <typename PointT> void
83 const PointCloud<PointT> &cloud, const Indices &indices,
84 const typename search::Search<PointT>::Ptr &tree, float tolerance, std::vector<PointIndices> &clusters,
85 unsigned int min_pts_per_cluster = 1, unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ());
86
87#if PCL_HAS_FLANN
88 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
89 /** \brief Decompose a region of space into clusters based on the euclidean distance between points, and the normal
90 * angular deviation between points. Each point added to the cluster is origin to another radius search. Each point
91 * within radius range will be compared to the origin in respect to normal angle and euclidean distance. If both
92 * are under their respective threshold the point will be added to the cluster. Generally speaking the cluster
93 * algorithm will not stop on smooth surfaces but on surfaces with sharp edges.
94 * \param cloud the point cloud message
95 * \param normals the point cloud message containing normal information
96 * \param tree the spatial locator (e.g., kd-tree) used for nearest neighbors searching
97 * \note the tree has to be created as a spatial locator on \a cloud
98 * \param tolerance the spatial cluster tolerance as a measure in the L2 Euclidean space
99 * \param clusters the resultant clusters containing point indices (as a vector of PointIndices)
100 * \param eps_angle the maximum allowed difference between normals in radians for cluster/region growing
101 * \param min_pts_per_cluster minimum number of points that a cluster may contain (default: 1)
102 * \param max_pts_per_cluster maximum number of points that a cluster may contain (default: max int)
103 * \ingroup segmentation
104 */
105 template <typename PointT, typename Normal>
106 PCL_DEPRECATED(1, 19, "use a search method inheriting from pcl::search::Search instead")
107 void
109 const PointCloud<PointT> &cloud, const PointCloud<Normal> &normals,
110 float tolerance, const typename KdTree<PointT>::Ptr &tree,
111 std::vector<PointIndices> &clusters, double eps_angle,
112 unsigned int min_pts_per_cluster = 1,
113 unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ())
114 {
115 if (tree->getInputCloud ()->size () != cloud.size ())
116 {
117 PCL_ERROR("[pcl::extractEuclideanClusters] Tree built for a different point "
118 "cloud dataset (%zu) than the input cloud (%zu)!\n",
119 static_cast<std::size_t>(tree->getInputCloud()->size()),
120 static_cast<std::size_t>(cloud.size()));
121 return;
122 }
123 if (cloud.size () != normals.size ())
124 {
125 PCL_ERROR("[pcl::extractEuclideanClusters] Number of points in the input point "
126 "cloud (%zu) different than normals (%zu)!\n",
127 static_cast<std::size_t>(cloud.size()),
128 static_cast<std::size_t>(normals.size()));
129 return;
130 }
131 // If tree gives sorted results, we can skip the first one because it is the query point itself
132 const std::size_t nn_start_idx = tree->getSortedResults () ? 1 : 0;
133 const double cos_eps_angle = std::cos (eps_angle); // compute this once instead of acos many times (faster)
134
135 // Create a bool vector of processed point indices, and initialize it to false
136 std::vector<bool> processed (cloud.size (), false);
137
138 Indices nn_indices;
139 std::vector<float> nn_distances;
140 // Process all points in the indices vector
141 for (std::size_t i = 0; i < cloud.size (); ++i)
142 {
143 if (processed[i])
144 continue;
145
146 Indices seed_queue;
147 int sq_idx = 0;
148 seed_queue.push_back (static_cast<index_t> (i));
149
150 processed[i] = true;
151
152 while (sq_idx < static_cast<int> (seed_queue.size ()))
153 {
154 // Search for sq_idx
155 if (!tree->radiusSearch (seed_queue[sq_idx], tolerance, nn_indices, nn_distances))
156 {
157 sq_idx++;
158 continue;
159 }
160
161 for (std::size_t j = nn_start_idx; j < nn_indices.size (); ++j)
162 {
163 if (processed[nn_indices[j]]) // Has this point been processed before ?
164 continue;
165
166 //processed[nn_indices[j]] = true;
167 // [-1;1]
168 double dot_p = normals[seed_queue[sq_idx]].normal[0] * normals[nn_indices[j]].normal[0] +
169 normals[seed_queue[sq_idx]].normal[1] * normals[nn_indices[j]].normal[1] +
170 normals[seed_queue[sq_idx]].normal[2] * normals[nn_indices[j]].normal[2];
171 if ( std::abs (dot_p) > cos_eps_angle )
172 {
173 processed[nn_indices[j]] = true;
174 seed_queue.push_back (nn_indices[j]);
175 }
176 }
177
178 sq_idx++;
179 }
180
181 // If this queue is satisfactory, add to the clusters
182 if (seed_queue.size () >= min_pts_per_cluster && seed_queue.size () <= max_pts_per_cluster)
183 {
185 r.indices.resize (seed_queue.size ());
186 for (std::size_t j = 0; j < seed_queue.size (); ++j)
187 r.indices[j] = seed_queue[j];
188
189 // After clustering, indices are out of order, so sort them
190 std::sort (r.indices.begin (), r.indices.end ());
191
192 r.header = cloud.header;
193 clusters.push_back (r); // We could avoid a copy by working directly in the vector
194 }
195 else
196 {
197 PCL_DEBUG("[pcl::extractEuclideanClusters] This cluster has %zu points, which is not between %u and %u points, so it is not a final cluster\n",
198 seed_queue.size (), min_pts_per_cluster, max_pts_per_cluster);
199 }
200 }
201 }
202
203
204 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
205 /** \brief Decompose a region of space into clusters based on the euclidean distance between points, and the normal
206 * angular deviation between points. Each point added to the cluster is origin to another radius search. Each point
207 * within radius range will be compared to the origin in respect to normal angle and euclidean distance. If both
208 * are under their respective threshold the point will be added to the cluster. Generally speaking the cluster
209 * algorithm will not stop on smooth surfaces but on surfaces with sharp edges.
210 * \param cloud the point cloud message
211 * \param normals the point cloud message containing normal information
212 * \param indices a list of point indices to use from \a cloud
213 * \param tree the spatial locator (e.g., kd-tree) used for nearest neighbors searching
214 * \note the tree has to be created as a spatial locator on \a cloud
215 * \param tolerance the spatial cluster tolerance as a measure in the L2 Euclidean space
216 * \param clusters the resultant clusters containing point indices (as PointIndices)
217 * \param eps_angle the maximum allowed difference between normals in radians for cluster/region growing
218 * \param min_pts_per_cluster minimum number of points that a cluster may contain (default: 1)
219 * \param max_pts_per_cluster maximum number of points that a cluster may contain (default: max int)
220 * \ingroup segmentation
221 */
222 template <typename PointT, typename Normal>
223 PCL_DEPRECATED(1, 19, "use a search method inheriting from pcl::search::Search instead")
224 void
226 const PointCloud<PointT> &cloud, const PointCloud<Normal> &normals,
227 const Indices &indices, const typename KdTree<PointT>::Ptr &tree,
228 float tolerance, std::vector<PointIndices> &clusters, double eps_angle,
229 unsigned int min_pts_per_cluster = 1,
230 unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ())
231 {
232 // \note If the tree was created over <cloud, indices>, we guarantee a 1-1 mapping between what the tree returns
233 //and indices[i]
234 if (tree->getInputCloud()->size() != cloud.size()) {
235 PCL_ERROR("[pcl::extractEuclideanClusters] Tree built for a different point "
236 "cloud dataset (%zu) than the input cloud (%zu)!\n",
237 static_cast<std::size_t>(tree->getInputCloud()->size()),
238 static_cast<std::size_t>(cloud.size()));
239 return;
240 }
241 if (tree->getIndices()->size() != indices.size()) {
242 PCL_ERROR("[pcl::extractEuclideanClusters] Tree built for a different set of "
243 "indices (%zu) than the input set (%zu)!\n",
244 static_cast<std::size_t>(tree->getIndices()->size()),
245 indices.size());
246 return;
247 }
248 if (cloud.size() != normals.size()) {
249 PCL_ERROR("[pcl::extractEuclideanClusters] Number of points in the input point "
250 "cloud (%zu) different than normals (%zu)!\n",
251 static_cast<std::size_t>(cloud.size()),
252 static_cast<std::size_t>(normals.size()));
253 return;
254 }
255 // If tree gives sorted results, we can skip the first one because it is the query point itself
256 const std::size_t nn_start_idx = tree->getSortedResults () ? 1 : 0;
257 const double cos_eps_angle = std::cos (eps_angle); // compute this once instead of acos many times (faster)
258 // Create a bool vector of processed point indices, and initialize it to false
259 std::vector<bool> processed (cloud.size (), false);
260
261 Indices nn_indices;
262 std::vector<float> nn_distances;
263 // Process all points in the indices vector
264 for (const auto& point_idx : indices)
265 {
266 if (processed[point_idx])
267 continue;
268
269 Indices seed_queue;
270 int sq_idx = 0;
271 seed_queue.push_back (point_idx);
272
273 processed[point_idx] = true;
274
275 while (sq_idx < static_cast<int> (seed_queue.size ()))
276 {
277 // Search for sq_idx
278 if (!tree->radiusSearch (cloud[seed_queue[sq_idx]], tolerance, nn_indices, nn_distances))
279 {
280 sq_idx++;
281 continue;
282 }
283
284 for (std::size_t j = nn_start_idx; j < nn_indices.size (); ++j)
285 {
286 if (processed[nn_indices[j]]) // Has this point been processed before ?
287 continue;
288
289 //processed[nn_indices[j]] = true;
290 // [-1;1]
291 double dot_p = normals[seed_queue[sq_idx]].normal[0] * normals[nn_indices[j]].normal[0] +
292 normals[seed_queue[sq_idx]].normal[1] * normals[nn_indices[j]].normal[1] +
293 normals[seed_queue[sq_idx]].normal[2] * normals[nn_indices[j]].normal[2];
294 if ( std::abs (dot_p) > cos_eps_angle )
295 {
296 processed[nn_indices[j]] = true;
297 seed_queue.push_back (nn_indices[j]);
298 }
299 }
300
301 sq_idx++;
302 }
303
304 // If this queue is satisfactory, add to the clusters
305 if (seed_queue.size () >= min_pts_per_cluster && seed_queue.size () <= max_pts_per_cluster)
306 {
308 r.indices.resize (seed_queue.size ());
309 for (std::size_t j = 0; j < seed_queue.size (); ++j)
310 r.indices[j] = seed_queue[j];
311
312 // After clustering, indices are out of order, so sort them
313 std::sort (r.indices.begin (), r.indices.end ());
314
315 r.header = cloud.header;
316 clusters.push_back (r);
317 }
318 else
319 {
320 PCL_DEBUG("[pcl::extractEuclideanClusters] This cluster has %zu points, which is not between %u and %u points, so it is not a final cluster\n",
321 seed_queue.size (), min_pts_per_cluster, max_pts_per_cluster);
322 }
323 }
324 }
325#endif // PCL_HAS_FLANN
326
327 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
328 /** \brief Decompose a region of space into clusters based on the euclidean distance between points, and the normal
329 * angular deviation between points. Each point added to the cluster is origin to another radius search. Each point
330 * within radius range will be compared to the origin in respect to normal angle and euclidean distance. If both
331 * are under their respective threshold the point will be added to the cluster. Generally speaking the cluster
332 * algorithm will not stop on smooth surfaces but on surfaces with sharp edges.
333 * \param cloud the point cloud message
334 * \param normals the point cloud message containing normal information
335 * \param tree the spatial locator (e.g., kd-tree) used for nearest neighbors searching
336 * \note the tree has to be created as a spatial locator on \a cloud
337 * \param tolerance the spatial cluster tolerance as a measure in the L2 Euclidean space
338 * \param clusters the resultant clusters containing point indices (as a vector of PointIndices)
339 * \param eps_angle the maximum allowed difference between normals in radians for cluster/region growing
340 * \param min_pts_per_cluster minimum number of points that a cluster may contain (default: 1)
341 * \param max_pts_per_cluster maximum number of points that a cluster may contain (default: max int)
342 * \ingroup segmentation
343 */
344 template <typename PointT, typename Normal>
345 void
347 const PointCloud<PointT> &cloud, const PointCloud<Normal> &normals,
348 float tolerance, const typename search::Search<PointT>::Ptr &tree,
349 std::vector<PointIndices> &clusters, double eps_angle,
350 unsigned int min_pts_per_cluster = 1,
351 unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ())
352 {
353 if (tree->getInputCloud ()->size () != cloud.size ())
354 {
355 PCL_ERROR("[pcl::extractEuclideanClusters] Tree built for a different point "
356 "cloud dataset (%zu) than the input cloud (%zu)!\n",
357 static_cast<std::size_t>(tree->getInputCloud()->size()),
358 static_cast<std::size_t>(cloud.size()));
359 return;
360 }
361 if (cloud.size () != normals.size ())
362 {
363 PCL_ERROR("[pcl::extractEuclideanClusters] Number of points in the input point "
364 "cloud (%zu) different than normals (%zu)!\n",
365 static_cast<std::size_t>(cloud.size()),
366 static_cast<std::size_t>(normals.size()));
367 return;
368 }
369 // If tree gives sorted results, we can skip the first one because it is the query point itself
370 const std::size_t nn_start_idx = tree->getSortedResults () ? 1 : 0;
371 const double cos_eps_angle = std::cos (eps_angle); // compute this once instead of acos many times (faster)
372
373 // Create a bool vector of processed point indices, and initialize it to false
374 std::vector<bool> processed (cloud.size (), false);
375
376 Indices nn_indices;
377 std::vector<float> nn_distances;
378 // Process all points in the indices vector
379 for (std::size_t i = 0; i < cloud.size (); ++i)
380 {
381 if (processed[i])
382 continue;
383
384 Indices seed_queue;
385 int sq_idx = 0;
386 seed_queue.push_back (static_cast<index_t> (i));
387
388 processed[i] = true;
389
390 while (sq_idx < static_cast<int> (seed_queue.size ()))
391 {
392 // Search for sq_idx
393 if (!tree->radiusSearch (cloud[seed_queue[sq_idx]], tolerance, nn_indices, nn_distances))
394 {
395 sq_idx++;
396 continue;
397 }
398
399 for (std::size_t j = nn_start_idx; j < nn_indices.size (); ++j)
400 {
401 if (processed[nn_indices[j]]) // Has this point been processed before ?
402 continue;
403
404 //processed[nn_indices[j]] = true;
405 // [-1;1]
406 double dot_p = normals[seed_queue[sq_idx]].normal[0] * normals[nn_indices[j]].normal[0] +
407 normals[seed_queue[sq_idx]].normal[1] * normals[nn_indices[j]].normal[1] +
408 normals[seed_queue[sq_idx]].normal[2] * normals[nn_indices[j]].normal[2];
409 if ( std::abs (dot_p) > cos_eps_angle )
410 {
411 processed[nn_indices[j]] = true;
412 seed_queue.push_back (nn_indices[j]);
413 }
414 }
415
416 sq_idx++;
417 }
418
419 // If this queue is satisfactory, add to the clusters
420 if (seed_queue.size () >= min_pts_per_cluster && seed_queue.size () <= max_pts_per_cluster)
421 {
423 r.indices.resize (seed_queue.size ());
424 for (std::size_t j = 0; j < seed_queue.size (); ++j)
425 r.indices[j] = seed_queue[j];
426
427 // After clustering, indices are out of order, so sort them
428 std::sort (r.indices.begin (), r.indices.end ());
429
430 r.header = cloud.header;
431 clusters.push_back (r); // We could avoid a copy by working directly in the vector
432 }
433 else
434 {
435 PCL_DEBUG("[pcl::extractEuclideanClusters] This cluster has %zu points, which is not between %u and %u points, so it is not a final cluster\n",
436 seed_queue.size (), min_pts_per_cluster, max_pts_per_cluster);
437 }
438 }
439 }
440
441
442 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
443 /** \brief Decompose a region of space into clusters based on the euclidean distance between points, and the normal
444 * angular deviation between points. Each point added to the cluster is origin to another radius search. Each point
445 * within radius range will be compared to the origin in respect to normal angle and euclidean distance. If both
446 * are under their respective threshold the point will be added to the cluster. Generally speaking the cluster
447 * algorithm will not stop on smooth surfaces but on surfaces with sharp edges.
448 * \param cloud the point cloud message
449 * \param normals the point cloud message containing normal information
450 * \param indices a list of point indices to use from \a cloud
451 * \param tree the spatial locator (e.g., kd-tree) used for nearest neighbors searching
452 * \note the tree has to be created as a spatial locator on \a cloud
453 * \param tolerance the spatial cluster tolerance as a measure in the L2 Euclidean space
454 * \param clusters the resultant clusters containing point indices (as PointIndices)
455 * \param eps_angle the maximum allowed difference between normals in radians for cluster/region growing
456 * \param min_pts_per_cluster minimum number of points that a cluster may contain (default: 1)
457 * \param max_pts_per_cluster maximum number of points that a cluster may contain (default: max int)
458 * \ingroup segmentation
459 */
460 template <typename PointT, typename Normal>
461 void
463 const PointCloud<PointT> &cloud, const PointCloud<Normal> &normals,
464 const Indices &indices, const typename search::Search<PointT>::Ptr &tree,
465 float tolerance, std::vector<PointIndices> &clusters, double eps_angle,
466 unsigned int min_pts_per_cluster = 1,
467 unsigned int max_pts_per_cluster = (std::numeric_limits<int>::max) ())
468 {
469 // \note If the tree was created over <cloud, indices>, we guarantee a 1-1 mapping between what the tree returns
470 //and indices[i]
471 if (tree->getInputCloud()->size() != cloud.size()) {
472 PCL_ERROR("[pcl::extractEuclideanClusters] Tree built for a different point "
473 "cloud dataset (%zu) than the input cloud (%zu)!\n",
474 static_cast<std::size_t>(tree->getInputCloud()->size()),
475 static_cast<std::size_t>(cloud.size()));
476 return;
477 }
478 const auto tree_indices = tree->getIndices();
479 if (!tree_indices) {
480 PCL_ERROR("[pcl::extractEuclideanClusters] Tree was built without indices, but an indices set was provided!\n");
481 return;
482 }
483 if (tree_indices->size() != indices.size()) {
484 PCL_ERROR("[pcl::extractEuclideanClusters] Tree built for a different set of "
485 "indices (%zu) than the input set (%zu)!\n",
486 static_cast<std::size_t>(tree_indices->size()),
487 indices.size());
488 return;
489 }
490 if (cloud.size() != normals.size()) {
491 PCL_ERROR("[pcl::extractEuclideanClusters] Number of points in the input point "
492 "cloud (%zu) different than normals (%zu)!\n",
493 static_cast<std::size_t>(cloud.size()),
494 static_cast<std::size_t>(normals.size()));
495 return;
496 }
497 // If tree gives sorted results, we can skip the first one because it is the query point itself
498 const std::size_t nn_start_idx = tree->getSortedResults () ? 1 : 0;
499 const double cos_eps_angle = std::cos (eps_angle); // compute this once instead of acos many times (faster)
500 // Create a bool vector of processed point indices, and initialize it to false
501 std::vector<bool> processed (cloud.size (), false);
502
503 Indices nn_indices;
504 std::vector<float> nn_distances;
505 // Process all points in the indices vector
506 for (const auto& point_idx : indices)
507 {
508 if (processed[point_idx])
509 continue;
510
511 Indices seed_queue;
512 int sq_idx = 0;
513 seed_queue.push_back (point_idx);
514
515 processed[point_idx] = true;
516
517 while (sq_idx < static_cast<int> (seed_queue.size ()))
518 {
519 // Search for sq_idx
520 if (!tree->radiusSearch (cloud[seed_queue[sq_idx]], tolerance, nn_indices, nn_distances))
521 {
522 sq_idx++;
523 continue;
524 }
525
526 for (std::size_t j = nn_start_idx; j < nn_indices.size (); ++j)
527 {
528 if (processed[nn_indices[j]]) // Has this point been processed before ?
529 continue;
530
531 //processed[nn_indices[j]] = true;
532 // [-1;1]
533 double dot_p = normals[seed_queue[sq_idx]].normal[0] * normals[nn_indices[j]].normal[0] +
534 normals[seed_queue[sq_idx]].normal[1] * normals[nn_indices[j]].normal[1] +
535 normals[seed_queue[sq_idx]].normal[2] * normals[nn_indices[j]].normal[2];
536 if ( std::abs (dot_p) > cos_eps_angle )
537 {
538 processed[nn_indices[j]] = true;
539 seed_queue.push_back (nn_indices[j]);
540 }
541 }
542
543 sq_idx++;
544 }
545
546 // If this queue is satisfactory, add to the clusters
547 if (seed_queue.size () >= min_pts_per_cluster && seed_queue.size () <= max_pts_per_cluster)
548 {
550 r.indices.resize (seed_queue.size ());
551 for (std::size_t j = 0; j < seed_queue.size (); ++j)
552 r.indices[j] = seed_queue[j];
553
554 // After clustering, indices are out of order, so sort them
555 std::sort (r.indices.begin (), r.indices.end ());
556
557 r.header = cloud.header;
558 clusters.push_back (r);
559 }
560 else
561 {
562 PCL_DEBUG("[pcl::extractEuclideanClusters] This cluster has %zu points, which is not between %u and %u points, so it is not a final cluster\n",
563 seed_queue.size (), min_pts_per_cluster, max_pts_per_cluster);
564 }
565 }
566 }
567
568 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
569 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
570 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
571 /** \brief @b EuclideanClusterExtraction represents a segmentation class for cluster extraction in an Euclidean sense.
572 * \author Radu Bogdan Rusu
573 * \ingroup segmentation
574 */
575 template <typename PointT>
577 {
579
580 public:
584
586 using KdTreePtr = typename KdTree::Ptr;
587
590
591 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
592 /** \brief Empty constructor. */
594
595 /** \brief Provide a pointer to the search object.
596 * \param[in] tree a pointer to the spatial search object.
597 */
598 inline void
600 {
601 tree_ = tree;
602 }
603
604 /** \brief Get a pointer to the search method used.
605 * @todo fix this for a generic search tree
606 */
607 inline KdTreePtr
609 {
610 return (tree_);
611 }
612
613 /** \brief Set the spatial cluster tolerance as a measure in the L2 Euclidean space
614 * \param[in] tolerance the spatial cluster tolerance as a measure in the L2 Euclidean space
615 */
616 inline void
617 setClusterTolerance (double tolerance)
618 {
619 cluster_tolerance_ = tolerance;
620 }
621
622 /** \brief Get the spatial cluster tolerance as a measure in the L2 Euclidean space. */
623 inline double
625 {
626 return (cluster_tolerance_);
627 }
628
629 /** \brief Set the minimum number of points that a cluster needs to contain in order to be considered valid.
630 * \param[in] min_cluster_size the minimum cluster size
631 */
632 inline void
634 {
635 min_pts_per_cluster_ = min_cluster_size;
636 }
637
638 /** \brief Get the minimum number of points that a cluster needs to contain in order to be considered valid. */
639 inline pcl::uindex_t
641 {
642 return (min_pts_per_cluster_);
643 }
644
645 /** \brief Set the maximum number of points that a cluster needs to contain in order to be considered valid.
646 * \param[in] max_cluster_size the maximum cluster size
647 */
648 inline void
650 {
651 max_pts_per_cluster_ = max_cluster_size;
652 }
653
654 /** \brief Get the maximum number of points that a cluster needs to contain in order to be considered valid. */
655 inline pcl::uindex_t
657 {
658 return (max_pts_per_cluster_);
659 }
660
661 /** \brief Cluster extraction in a PointCloud given by <setInputCloud (), setIndices ()>
662 * \param[out] clusters the resultant point clusters
663 */
664 void
665 extract (std::vector<PointIndices> &clusters);
666
667 protected:
668 // Members derived from the base class
673
674 /** \brief A pointer to the spatial search object. */
675 KdTreePtr tree_{nullptr};
676
677 /** \brief The spatial cluster tolerance as a measure in the L2 Euclidean space. */
679
680 /** \brief The minimum number of points that a cluster needs to contain in order to be considered valid (default = 1). */
682
683 /** \brief The maximum number of points that a cluster needs to contain in order to be considered valid (default = MAXINT). */
684 pcl::uindex_t max_pts_per_cluster_{std::numeric_limits<pcl::uindex_t>::max()};
685
686 /** \brief Class getName method. */
687 virtual std::string getClassName () const { return ("EuclideanClusterExtraction"); }
688
689 };
690
691 /** \brief Sort clusters method (for std::sort).
692 * \ingroup segmentation
693 */
694 inline bool
696 {
697 return (a.indices.size () < b.indices.size ());
698 }
699}
700
701#ifdef PCL_NO_PRECOMPILE
702#include <pcl/segmentation/impl/extract_clusters.hpp>
703#endif
EuclideanClusterExtraction represents a segmentation class for cluster extraction in an Euclidean sen...
pcl::uindex_t getMaxClusterSize() const
Get the maximum number of points that a cluster needs to contain in order to be considered valid.
double cluster_tolerance_
The spatial cluster tolerance as a measure in the L2 Euclidean space.
pcl::uindex_t max_pts_per_cluster_
The maximum number of points that a cluster needs to contain in order to be considered valid (default...
typename PointCloud::Ptr PointCloudPtr
typename PointCloud::ConstPtr PointCloudConstPtr
void extract(std::vector< PointIndices > &clusters)
Cluster extraction in a PointCloud given by <setInputCloud (), setIndices ()>
EuclideanClusterExtraction()=default
Empty constructor.
double getClusterTolerance() const
Get the spatial cluster tolerance as a measure in the L2 Euclidean space.
virtual std::string getClassName() const
Class getName method.
void setClusterTolerance(double tolerance)
Set the spatial cluster tolerance as a measure in the L2 Euclidean space.
pcl::uindex_t min_pts_per_cluster_
The minimum number of points that a cluster needs to contain in order to be considered valid (default...
void setSearchMethod(const KdTreePtr &tree)
Provide a pointer to the search object.
PointIndices::ConstPtr PointIndicesConstPtr
KdTreePtr getSearchMethod() const
Get a pointer to the search method used.
void setMaxClusterSize(pcl::uindex_t max_cluster_size)
Set the maximum number of points that a cluster needs to contain in order to be considered valid.
void setMinClusterSize(pcl::uindex_t min_cluster_size)
Set the minimum number of points that a cluster needs to contain in order to be considered valid.
KdTreePtr tree_
A pointer to the spatial search object.
pcl::PointCloud< PointT > PointCloud
pcl::uindex_t getMinClusterSize() const
Get the minimum number of points that a cluster needs to contain in order to be considered valid.
PCL base class.
Definition pcl_base.h:70
PointCloudConstPtr input_
The input point cloud dataset.
Definition pcl_base.h:147
IndicesPtr indices_
A pointer to the vector of point indices to use.
Definition pcl_base.h:150
bool initCompute()
This method should get called before starting the actual computation.
Definition pcl_base.hpp:138
bool deinitCompute()
This method should get called after finishing the actual computation.
Definition pcl_base.hpp:175
PointCloud represents the base class in PCL for storing collections of 3D points.
void push_back(const PointT &pt)
Insert a new point in the cloud, at the end of the container.
pcl::PCLHeader header
The point cloud header.
std::size_t size() const
shared_ptr< PointCloud< PointT > > Ptr
shared_ptr< const PointCloud< PointT > > ConstPtr
Generic search class.
Definition search.h:75
virtual bool getSortedResults()
Gets whether the results should be sorted (ascending in the distance) or not Otherwise the results ma...
Definition search.hpp:68
virtual IndicesConstPtr getIndices() const
Get a pointer to the vector of indices used.
Definition search.h:131
shared_ptr< pcl::search::Search< PointT > > Ptr
Definition search.h:81
virtual PointCloudConstPtr getInputCloud() const
Get a pointer to the input point cloud dataset.
Definition search.h:124
virtual int radiusSearch(const PointT &point, double radius, Indices &k_indices, std::vector< float > &k_sqr_distances, unsigned int max_nn=0) const =0
Search for all the nearest neighbors of the query point in a given radius.
void extractEuclideanClusters(const PointCloud< PointT > &cloud, const typename search::Search< PointT >::Ptr &tree, float tolerance, std::vector< PointIndices > &clusters, unsigned int min_pts_per_cluster=1, unsigned int max_pts_per_cluster=(std::numeric_limits< int >::max)())
Decompose a region of space into clusters based on the Euclidean distance between points.
bool comparePointClusters(const pcl::PointIndices &a, const pcl::PointIndices &b)
Sort clusters method (for std::sort).
detail::int_type_t< detail::index_type_size, false > uindex_t
Type used for an unsigned index in PCL.
Definition types.h:120
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.
Definition types.h:112
IndicesAllocator<> Indices
Type used for indices in PCL.
Definition types.h:133
#define PCL_DEPRECATED(Major, Minor, Message)
macro for compatibility across compilers and help remove old deprecated items for the Major....
Definition pcl_macros.h:156
shared_ptr< ::pcl::PointIndices > Ptr
::pcl::PCLHeader header
shared_ptr< const ::pcl::PointIndices > ConstPtr
A point structure representing Euclidean xyz coordinates, and the RGB color.