Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
extract_clusters.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2009, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage, Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $Id: extract_clusters.hpp 6155 2012-07-04 23:10:00Z aichim $
35  *
36  */
37 
38 #ifndef PCL_SEGMENTATION_IMPL_EXTRACT_CLUSTERS_H_
39 #define PCL_SEGMENTATION_IMPL_EXTRACT_CLUSTERS_H_
40 
42 
44 template <typename PointT> void
46  const boost::shared_ptr<search::Search<PointT> > &tree,
47  float tolerance, std::vector<PointIndices> &clusters,
48  unsigned int min_pts_per_cluster,
49  unsigned int max_pts_per_cluster)
50 {
51  if (tree->getInputCloud ()->points.size () != cloud.points.size ())
52  {
53  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 ());
54  return;
55  }
56  // Create a bool vector of processed point indices, and initialize it to false
57  std::vector<bool> processed (cloud.points.size (), false);
58 
59  std::vector<int> nn_indices;
60  std::vector<float> nn_distances;
61  // Process all points in the indices vector
62  for (int i = 0; i < static_cast<int> (cloud.points.size ()); ++i)
63  {
64  if (processed[i])
65  continue;
66 
67  std::vector<int> seed_queue;
68  int sq_idx = 0;
69  seed_queue.push_back (i);
70 
71  processed[i] = true;
72 
73  while (sq_idx < static_cast<int> (seed_queue.size ()))
74  {
75  // Search for sq_idx
76  if (!tree->radiusSearch (seed_queue[sq_idx], tolerance, nn_indices, nn_distances))
77  {
78  sq_idx++;
79  continue;
80  }
81 
82  for (size_t j = 1; j < nn_indices.size (); ++j) // nn_indices[0] should be sq_idx
83  {
84  if (nn_indices[j] == -1 || processed[nn_indices[j]]) // Has this point been processed before ?
85  continue;
86 
87  // Perform a simple Euclidean clustering
88  seed_queue.push_back (nn_indices[j]);
89  processed[nn_indices[j]] = true;
90  }
91 
92  sq_idx++;
93  }
94 
95  // If this queue is satisfactory, add to the clusters
96  if (seed_queue.size () >= min_pts_per_cluster && seed_queue.size () <= max_pts_per_cluster)
97  {
99  r.indices.resize (seed_queue.size ());
100  for (size_t j = 0; j < seed_queue.size (); ++j)
101  r.indices[j] = seed_queue[j];
102 
103  // These two lines should not be needed: (can anyone confirm?) -FF
104  std::sort (r.indices.begin (), r.indices.end ());
105  r.indices.erase (std::unique (r.indices.begin (), r.indices.end ()), r.indices.end ());
106 
107  r.header = cloud.header;
108  clusters.push_back (r); // We could avoid a copy by working directly in the vector
109  }
110  }
111 }
112 
114 
115 template <typename PointT> void
117  const std::vector<int> &indices,
118  const boost::shared_ptr<search::Search<PointT> > &tree,
119  float tolerance, std::vector<PointIndices> &clusters,
120  unsigned int min_pts_per_cluster,
121  unsigned int max_pts_per_cluster)
122 {
123  // \note If the tree was created over <cloud, indices>, we guarantee a 1-1 mapping between what the tree returns
124  //and indices[i]
125  if (tree->getInputCloud ()->points.size () != cloud.points.size ())
126  {
127  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 ());
128  return;
129  }
130  if (tree->getIndices ()->size () != indices.size ())
131  {
132  PCL_ERROR ("[pcl::extractEuclideanClusters] Tree built for a different set of indices (%zu) than the input set (%zu)!\n", tree->getIndices ()->size (), indices.size ());
133  return;
134  }
135 
136  // Create a bool vector of processed point indices, and initialize it to false
137  std::vector<bool> processed (cloud.points.size (), false);
138 
139  std::vector<int> nn_indices;
140  std::vector<float> nn_distances;
141  // Process all points in the indices vector
142  for (int i = 0; i < static_cast<int> (indices.size ()); ++i)
143  {
144  if (processed[indices[i]])
145  continue;
146 
147  std::vector<int> seed_queue;
148  int sq_idx = 0;
149  seed_queue.push_back (indices[i]);
150 
151  processed[indices[i]] = true;
152 
153  while (sq_idx < static_cast<int> (seed_queue.size ()))
154  {
155  // Search for sq_idx
156  int ret = tree->radiusSearch (cloud.points[seed_queue[sq_idx]], tolerance, nn_indices, nn_distances);
157  if( ret == -1)
158  {
159  PCL_ERROR("[pcl::extractEuclideanClusters] Received error code -1 from radiusSearch\n");
160  exit(0);
161  }
162  if (!ret)
163  {
164  sq_idx++;
165  continue;
166  }
167 
168  for (size_t j = 1; j < nn_indices.size (); ++j) // nn_indices[0] should be sq_idx
169  {
170  if (nn_indices[j] == -1 || processed[nn_indices[j]]) // Has this point been processed before ?
171  continue;
172 
173  // Perform a simple Euclidean clustering
174  seed_queue.push_back (nn_indices[j]);
175  processed[nn_indices[j]] = true;
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 (size_t j = 0; j < seed_queue.size (); ++j)
187  // This is the only place where indices come into play
188  r.indices[j] = seed_queue[j];
189 
190  // These two lines should not be needed: (can anyone confirm?) -FF
191  //r.indices.assign(seed_queue.begin(), seed_queue.end());
192  std::sort (r.indices.begin (), r.indices.end ());
193  r.indices.erase (std::unique (r.indices.begin (), r.indices.end ()), r.indices.end ());
194 
195  r.header = cloud.header;
196  clusters.push_back (r); // We could avoid a copy by working directly in the vector
197  }
198  }
199 }
200 
204 
205 template <typename PointT> void
206 pcl::EuclideanClusterExtraction<PointT>::extract (std::vector<PointIndices> &clusters)
207 {
208  if (!initCompute () ||
209  (input_ != 0 && input_->points.empty ()) ||
210  (indices_ != 0 && indices_->empty ()))
211  {
212  clusters.clear ();
213  return;
214  }
215 
216  // Initialize the spatial locator
217  if (!tree_)
218  {
219  if (input_->isOrganized ())
220  tree_.reset (new pcl::search::OrganizedNeighbor<PointT> ());
221  else
222  tree_.reset (new pcl::search::KdTree<PointT> (false));
223  }
224 
225  // Send the input dataset to the spatial locator
226  tree_->setInputCloud (input_, indices_);
227  extractEuclideanClusters (*input_, *indices_, tree_, static_cast<float> (cluster_tolerance_), clusters, min_pts_per_cluster_, max_pts_per_cluster_);
228 
229  //tree_->setInputCloud (input_);
230  //extractEuclideanClusters (*input_, tree_, cluster_tolerance_, clusters, min_pts_per_cluster_, max_pts_per_cluster_);
231 
232  // Sort the clusters based on their size (largest one first)
233  std::sort (clusters.rbegin (), clusters.rend (), comparePointClusters);
234 
235  deinitCompute ();
236 }
237 
238 #define PCL_INSTANTIATE_EuclideanClusterExtraction(T) template class PCL_EXPORTS pcl::EuclideanClusterExtraction<T>;
239 #define PCL_INSTANTIATE_extractEuclideanClusters(T) template void PCL_EXPORTS pcl::extractEuclideanClusters<T>(const pcl::PointCloud<T> &, const boost::shared_ptr<pcl::search::Search<T> > &, float , std::vector<pcl::PointIndices> &, unsigned int, unsigned int);
240 #define PCL_INSTANTIATE_extractEuclideanClusters_indices(T) template void PCL_EXPORTS pcl::extractEuclideanClusters<T>(const pcl::PointCloud<T> &, const std::vector<int> &, const boost::shared_ptr<pcl::search::Search<T> > &, float , std::vector<pcl::PointIndices> &, unsigned int, unsigned int);
241 
242 #endif // PCL_EXTRACT_CLUSTERS_IMPL_H_