euclidean_cluster_extraction_nodelet.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2013, Ryohei Ueda and JSK Lab
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/o2r other materials provided
16  * with the distribution.
17  * * Neither the name of the JSK Lab 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 
38 
39 using namespace std;
40 using namespace pcl;
41 
42 namespace jsk_pcl_ros
43 {
44 
45  void EuclideanClustering::downsample_cloud(
46  const pcl::PointCloud<pcl::PointXYZ>::Ptr& original_cloud,
47  pcl::PointCloud<pcl::PointXYZ>::Ptr& sampled_cloud,
48  std::vector<std::vector<int> >& sampled_to_original_indices,
49  std::vector<int>& original_to_sampled_indices,
50  double leaf_size)
51  {
52  pcl::VoxelGrid<pcl::PointXYZ> voxel;
53  voxel.setLeafSize(leaf_size, leaf_size, leaf_size);
54  voxel.setSaveLeafLayout(true);
55  voxel.setInputCloud(original_cloud);
56  voxel.filter(*sampled_cloud);
57  sampled_to_original_indices.resize(original_cloud->points.size());
58  original_to_sampled_indices.resize(original_cloud->points.size());
59  std::fill(original_to_sampled_indices.begin(),
60  original_to_sampled_indices.end(),
61  -1);
62  std::fill(sampled_to_original_indices.begin(),
63  sampled_to_original_indices.end(),
64  std::vector<int>());
65  for (size_t i = 0; i < original_cloud->points.size(); ++i) {
66  pcl::PointXYZ p = original_cloud->points[i];
67  if (std::isnan(p.x) || std::isnan(p.y) || std::isnan(p.z)) {
68  continue;
69  }
70  int index = voxel.getCentroidIndex(p);
71  if (index == -1) {
72  continue;
73  }
74  original_to_sampled_indices[i] = index;
75  sampled_to_original_indices[index].push_back(i);
76  }
77  }
78 
79  void EuclideanClustering::clusteringClusterIndices(
80  pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud,
81  std::vector<pcl::PointIndices::Ptr> &cluster_indices,
82  std::vector<pcl::PointIndices> &clustered_indices) {
83 
84  boost::mutex::scoped_lock lock(mutex_);
85 
86  clustered_indices.clear();
87 
88 
89  pcl::PointCloud<pcl::PointXYZ>::Ptr preprocessed_cloud(
90  new pcl::PointCloud<pcl::PointXYZ>);
91  if (downsample_) {
92  downsample_cloud(cloud,
93  preprocessed_cloud,
94  downsample_to_original_indices_,
95  original_to_downsample_indices_,
96  leaf_size_);
97 
98  } else {
99  preprocessed_cloud = cloud;
100  }
101 
102  if (preprocessed_cloud->points.size() == 0) {
103  return;
104  }
105 
106  for(pcl::PointIndices::Ptr point_indices : cluster_indices){
107  pcl::PointIndices::Ptr nonnan_indices (new pcl::PointIndices);
108  for(int original_index : point_indices->indices) {
109  int index;
110  if (downsample_) {
111  index = original_to_downsample_indices_[original_index];
112  } else {
113  index = original_index;
114  }
115  if (index == -1) {
116  continue;
117  }
118 
119  pcl::PointXYZ p = preprocessed_cloud->points[index];
120  if (!std::isnan(p.x) && !std::isnan(p.y) && !std::isnan(p.z)) {
121  nonnan_indices->indices.push_back(index);
122  }
123  }
124  removeDuplicatedIndices(nonnan_indices);
125 
126  pcl::PointIndices result_point_indices;
127  if (nonnan_indices->indices.size() > 0) {
128  // Create the filtering object
129  pcl::PointCloud<pcl::PointXYZ>::Ptr filtered_cloud(new pcl::PointCloud<pcl::PointXYZ>);
130  {
131  pcl::ExtractIndices<pcl::PointXYZ> extract;
132  extract.setInputCloud(preprocessed_cloud);
133  extract.setIndices (nonnan_indices);
134  extract.setNegative(false);
135  extract.filter (*filtered_cloud);
136  }
137 
139  if (filtered_cloud->points.size() > 0) {
140  jsk_topic_tools::ScopedTimer timer = kdtree_acc_.scopedTimer();
141 #if ( PCL_MAJOR_VERSION >= 1 && PCL_MINOR_VERSION >= 5 )
142  pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
143  tree = boost::make_shared< pcl::search::KdTree<pcl::PointXYZ> > ();
144 #else
145  pcl::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::KdTreeFLANN<pcl::PointXYZ>);
146  tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointXYZ> > ();
147 #endif
148  tree->setInputCloud(filtered_cloud);
149  impl.setClusterTolerance(tolerance);
150  impl.setMinClusterSize(minsize_);
151  impl.setMaxClusterSize(maxsize_);
152  impl.setSearchMethod(tree);
153  impl.setInputCloud(filtered_cloud);
154  }
155 
156  std::vector<pcl::PointIndices> output_indices;
157  {
158  jsk_topic_tools::ScopedTimer timer = segmentation_acc_.scopedTimer();
159  impl.extract(output_indices);
160  if (downsample_) {
161  for (size_t i = 0; i < output_indices.size(); ++i) {
162  pcl::PointIndices::Ptr tmp_indices(new pcl::PointIndices);
163  for (size_t j = 0; j < output_indices.at(i).indices.size(); ++j) {
164  tmp_indices->indices.insert(
165  tmp_indices->indices.end(),
166  downsample_to_original_indices_[nonnan_indices->indices[output_indices.at(i).indices[j]]].begin(),
167  downsample_to_original_indices_[nonnan_indices->indices[output_indices.at(i).indices[j]]].end());
168  }
169  removeDuplicatedIndices(tmp_indices);
170  output_indices[i] = *tmp_indices;
171  }
172  } else {
173  for (size_t i = 0; i < output_indices.size(); ++i) {
174  pcl::PointIndices tmp_indices;
175  tmp_indices.indices.resize( output_indices.at(i).indices.size());
176  for (size_t j = 0; j < output_indices.at(i).indices.size(); ++j) {
177  tmp_indices.indices[j] = nonnan_indices->indices[output_indices.at(i).indices[j]];
178  }
179  output_indices[i] = tmp_indices;
180  }
181  }
182  }
183  std::vector<int> result_indices;
184  std::vector<int> examine_indices;
185  switch (cluster_filter_type_) {
186  case jsk_pcl_ros::EuclideanClustering_All: {
187  for (size_t i_e = 0; i_e < output_indices.size(); ++i_e) {
188  examine_indices.push_back(i_e);
189  }
190  break;
191  }
192  case jsk_pcl_ros::EuclideanClustering_MaxSize: {
193  // take maximum size of cluster
194  int size = 0;
195  int index = 0;
196  for(size_t i=0; i < output_indices.size(); i++){
197  if(output_indices[i].indices.size() > size){
198  size = output_indices[i].indices.size();
199  index = i;
200  }
201  }
202  examine_indices.push_back(index);
203  break;
204  }
205  }
206  for (int index : examine_indices) {
207  result_point_indices.indices = output_indices.at(index).indices;
208  clustered_indices.push_back(result_point_indices);
209  }
210  } else {
211  clustered_indices.push_back(result_point_indices);
212  }
213  }
214  }
215 
216  void EuclideanClustering::extract(
217  const sensor_msgs::PointCloud2ConstPtr &input)
218  {
219  vital_checker_->poke();
220  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud
221  (new pcl::PointCloud<pcl::PointXYZ>);
222  pcl::fromROSMsg(*input, *cloud);
223 
224  pcl::PointIndices::Ptr whole_indices(new pcl::PointIndices);
225  whole_indices->indices.resize(input->height * input->width);
226  for (size_t i = 0; i < input->height * input->width; ++i) {
227  whole_indices->indices[i] = i;
228  }
229  std::vector<pcl::PointIndices::Ptr> cluster_indices{whole_indices};
230  std::vector<pcl::PointIndices> clustered_indices;
231  clusteringClusterIndices(cloud,
232  cluster_indices,
233  clustered_indices);
234 
235  // Publish result indices
236  jsk_recognition_msgs::ClusterPointIndices result;
237  result.cluster_indices.resize(clustered_indices.size());
238  cluster_counter_.add(clustered_indices.size());
239  result.header = input->header;
240  if (cogs_.size() != 0 && cogs_.size() == clustered_indices.size()) {
241  // tracking the labels
242  //ROS_INFO("computing distance matrix");
243  // compute distance matrix
244  // D[i][j] --> distance between the i-th previous cluster
245  // and the current j-th cluster
246  Vector4fVector new_cogs;
247  computeCentroidsOfClusters(new_cogs, cloud, clustered_indices);
248  double D[cogs_.size() * new_cogs.size()];
249  computeDistanceMatrix(D, cogs_, new_cogs);
250  std::vector<int> pivot_table = buildLabelTrackingPivotTable(D, cogs_, new_cogs, label_tracking_tolerance);
251  if (pivot_table.size() != 0) {
252  clustered_indices = pivotClusterIndices(pivot_table, clustered_indices);
253  }
254  }
255  Vector4fVector tmp_cogs;
256  computeCentroidsOfClusters(tmp_cogs, cloud, clustered_indices); // NB: not efficient
257  cogs_ = tmp_cogs;
258 
259  for (size_t i = 0; i < clustered_indices.size(); i++) {
260 #if ROS_VERSION_MINIMUM(1, 10, 0)
261  // hydro and later
262  result.cluster_indices[i].header
263  = pcl_conversions::fromPCL(clustered_indices[i].header);
264 #else
265  // groovy
266  result.cluster_indices[i].header = clustered_indices[i].header;
267 #endif
268  result.cluster_indices[i].indices = clustered_indices[i].indices;
269  }
270 
271  result_pub_.publish(result);
272 
273  jsk_recognition_msgs::Int32Stamped::Ptr cluster_num_msg (new jsk_recognition_msgs::Int32Stamped);
274  cluster_num_msg->header = input->header;
275  cluster_num_msg->data = clustered_indices.size();
276  cluster_num_pub_.publish(cluster_num_msg);
277 
278  diagnostic_updater_->update();
279  }
280 
281  void EuclideanClustering::multi_extract(
282  const jsk_recognition_msgs::ClusterPointIndices::ConstPtr& input_cluster_indices,
283  const sensor_msgs::PointCloud2::ConstPtr& input) {
284  vital_checker_->poke();
285  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud
286  (new pcl::PointCloud<pcl::PointXYZ>);
287  pcl::fromROSMsg(*input, *cloud);
288 
289  std::vector<pcl::PointIndices::Ptr> cluster_indices =
290  pcl_conversions::convertToPCLPointIndices(input_cluster_indices->cluster_indices);
291  std::vector<pcl::PointIndices> clustered_indices;
292  clusteringClusterIndices(cloud,
293  cluster_indices,
294  clustered_indices);
295 
296  // Publish result indices
297  jsk_recognition_msgs::ClusterPointIndices result;
298  result.cluster_indices.resize(clustered_indices.size());
299  cluster_counter_.add(clustered_indices.size());
300  result.header = input->header;
301 
302  for (size_t i = 0; i < clustered_indices.size(); i++) {
303 #if ROS_VERSION_MINIMUM(1, 10, 0)
304  // hydro and later
305  result.cluster_indices[i].header
306  = pcl_conversions::fromPCL(clustered_indices[i].header);
307 #else
308  // groovy
309  result.cluster_indices[i].header = clustered_indices[i].header;
310 #endif
311  result.cluster_indices[i].indices = clustered_indices[i].indices;
312  }
313 
314  result_pub_.publish(result);
315 
316  jsk_recognition_msgs::Int32Stamped::Ptr cluster_num_msg (new jsk_recognition_msgs::Int32Stamped);
317  cluster_num_msg->header = input->header;
318  cluster_num_msg->data = clustered_indices.size();
319  cluster_num_pub_.publish(cluster_num_msg);
320 
321  diagnostic_updater_->update();
322  }
323 
324  bool EuclideanClustering::serviceCallback(
325  jsk_recognition_msgs::EuclideanSegment::Request &req,
326  jsk_recognition_msgs::EuclideanSegment::Response &res)
327  {
328  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
329  pcl::fromROSMsg(req.input, *cloud);
330 
331 #if ( PCL_MAJOR_VERSION >= 1 && PCL_MINOR_VERSION >= 5 )
332  pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
333  tree = boost::make_shared< pcl::search::KdTree<pcl::PointXYZ> > ();
334 #else
335  pcl::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::KdTreeFLANN<pcl::PointXYZ>);
336  tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointXYZ> > ();
337 #endif
338 
339  vector<pcl::PointIndices> cluster_indices;
341  double tor;
342  if ( req.tolerance < 0) {
343  tor = tolerance;
344  } else {
345  tor = req.tolerance;
346  }
347  impl.setClusterTolerance (tor);
348  impl.setMinClusterSize (minsize_);
349  impl.setMaxClusterSize (maxsize_);
350  impl.setSearchMethod (tree);
351  impl.setInputCloud (cloud);
352  impl.extract (cluster_indices);
353 
354  res.output.resize( cluster_indices.size() );
355 #if ( PCL_MAJOR_VERSION >= 1 && PCL_MINOR_VERSION >= 7 )
356  pcl::PCLPointCloud2::Ptr pcl_cloud(new pcl::PCLPointCloud2);
357  pcl_conversions::toPCL(req.input, *pcl_cloud);
358  pcl::ExtractIndices<pcl::PCLPointCloud2> ex;
359  ex.setInputCloud(pcl_cloud);
360 #else
361  pcl::ExtractIndices<sensor_msgs::PointCloud2> ex;
362  ex.setInputCloud ( boost::make_shared< sensor_msgs::PointCloud2 > (req.input) );
363 #endif
364  for ( size_t i = 0; i < cluster_indices.size(); i++ ) {
365  ex.setIndices ( boost::make_shared< pcl::PointIndices > (cluster_indices[i]) );
366  ex.setNegative ( false );
367 #if ( PCL_MAJOR_VERSION >= 1 && PCL_MINOR_VERSION >= 7 )
368  pcl::PCLPointCloud2 output_cloud;
369  ex.filter ( output_cloud );
370  pcl_conversions::fromPCL(output_cloud, res.output[i]);
371 #else
372  ex.filter ( res.output[i] );
373 #endif
374  }
375  return true;
376  }
377 
378  void EuclideanClustering::onInit()
379  {
380  DiagnosticNodelet::onInit();
381 
382  pnh_->param("multi", multi_, false);
383  pnh_->param("approximate_sync", approximate_sync_, false);
384  pnh_->param("queue_size", queue_size_, 20);
385 
387  // dynamic reconfigure
389  srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
390  dynamic_reconfigure::Server<Config>::CallbackType f =
391  boost::bind (&EuclideanClustering::configCallback, this, _1, _2);
392  srv_->setCallback (f);
393 
395  // Publisher
397  result_pub_ = advertise<jsk_recognition_msgs::ClusterPointIndices> (*pnh_, "output", 1);
398  cluster_num_pub_ = advertise<jsk_recognition_msgs::Int32Stamped> (*pnh_, "cluster_num", 1);
399  service_ = pnh_->advertiseService(pnh_->resolveName("euclidean_clustering"),
400  &EuclideanClustering::serviceCallback, this);
401 
402  onInitPostProcess();
403  }
404 
405  void EuclideanClustering::subscribe()
406  {
408  // Subscription
410  if (multi_) {
411  sub_cluster_indices_.subscribe(*pnh_, "input/cluster_indices", 1);
412  sub_point_cloud_.subscribe(*pnh_, "input", 1);
413  if (approximate_sync_) {
414  async_ = boost::make_shared<message_filters::Synchronizer<ApproximateSyncPolicy> >(queue_size_);
415  async_->connectInput(sub_cluster_indices_, sub_point_cloud_);
416  async_->registerCallback(boost::bind(&EuclideanClustering::multi_extract, this, _1, _2));
417  } else {
418  sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(queue_size_);
419  sync_->connectInput(sub_cluster_indices_, sub_point_cloud_);
420  sync_->registerCallback(boost::bind(&EuclideanClustering::multi_extract, this, _1, _2));
421  }
422  } else {
423  sub_input_ = pnh_->subscribe("input", 1, &EuclideanClustering::extract, this);
424  }
425  }
426 
427  void EuclideanClustering::unsubscribe()
428  {
429  if (multi_) {
430  sub_cluster_indices_.unsubscribe();
431  sub_point_cloud_.unsubscribe();
432  } else {
433  sub_input_.shutdown();
434  }
435  }
436 
437  void EuclideanClustering::updateDiagnostic(
439  {
440  if (vital_checker_->isAlive()) {
441  stat.summary(
442  diagnostic_msgs::DiagnosticStatus::OK,
443  "EuclideanSegmentation running");
444 
446  "Kdtree Construction", kdtree_acc_, stat);
448  "Euclidean Segmentation", segmentation_acc_, stat);
449  stat.add("Cluster Num (Avg.)", cluster_counter_.mean());
450  stat.add("Max Size of the cluster", maxsize_);
451  stat.add("Min Size of the cluster", minsize_);
452  stat.add("Cluster tolerance", tolerance);
453  stat.add("Tracking tolerance", label_tracking_tolerance);
454  stat.add("MultiEuclideanClustering", multi_);
455  stat.add("Downsample enable", downsample_);
456  if (downsample_) {
457  stat.add("Leaf size", leaf_size_);
458  }
459  }
460  DiagnosticNodelet::updateDiagnostic(stat);
461  }
462 
463  void EuclideanClustering::configCallback (Config &config, uint32_t level)
464  {
465  boost::mutex::scoped_lock lock(mutex_);
466  tolerance = config.tolerance;
467  label_tracking_tolerance = config.label_tracking_tolerance;
468  maxsize_ = config.max_size;
469  minsize_ = config.min_size;
470  cluster_filter_type_ = config.cluster_filter;
471  // downsample group
472  downsample_ = config.downsample_enable;
473  leaf_size_ = config.leaf_size;
474  }
475 
476  std::vector<pcl::PointIndices> EuclideanClustering::pivotClusterIndices(
477  std::vector<int>& pivot_table,
478  std::vector<pcl::PointIndices>& cluster_indices)
479  {
480  std::vector<pcl::PointIndices> new_cluster_indices;
481  new_cluster_indices.resize(pivot_table.size());
482  for (size_t i = 0; i < pivot_table.size(); i++) {
483  new_cluster_indices[i] = cluster_indices[pivot_table[i]];
484  }
485  return new_cluster_indices;
486  }
487  std::vector<int> EuclideanClustering::buildLabelTrackingPivotTable(
488  double* D, Vector4fVector cogs, Vector4fVector new_cogs,
489  double label_tracking_tolerance)
490  {
491  std::vector<int> pivot_table;
492  // initialize pivot table
493  pivot_table.resize(cogs.size());
494  for (size_t i = 0; i < pivot_table.size(); i++)
495  pivot_table[i] = i;
496  for (size_t pivot_counter = 0; pivot_counter < pivot_table.size();
497  pivot_counter++)
498  {
499  double minimum_distance = DBL_MAX;
500  size_t minimum_previous_index = 0;
501  size_t minimum_next_index = 0;
502  for (size_t i = 0; i < cogs.size(); i++)
503  {
504  for (size_t j = 0; j < new_cogs.size(); j++)
505  {
506  double distance = D[i * cogs.size() + j];
507  //ROS_INFO("distance %lux%lu: %f", i, j, distance);
508  if (distance < minimum_distance)
509  {
510  minimum_distance = distance;
511  minimum_previous_index = i;
512  minimum_next_index = j;
513  }
514  }
515  }
516  if (minimum_distance > label_tracking_tolerance)
517  {
518  // ROS_WARN("minimum tracking distance exceeds tolerance: %f > %f",
519  // minimum_distance, label_tracking_tolerance);
520  std::vector<int> dummy;
521  return dummy;
522  }
523  pivot_table[minimum_previous_index] = minimum_next_index;
524  // fill the D matrix with DBL_MAX
525  for (size_t j = 0; j < new_cogs.size(); j++)
526  {
527  D[minimum_previous_index * cogs.size() + j] = DBL_MAX;
528  }
529  }
530  return pivot_table;
531  }
532 
533  void EuclideanClustering::computeDistanceMatrix(
534  double* D,
535  Vector4fVector& old_cogs,
536  Vector4fVector& new_cogs)
537  {
538  for (size_t i = 0; i < old_cogs.size(); i++) {
539  Eigen::Vector4f previous_cog = old_cogs[i];
540  for (size_t j = 0; j < new_cogs.size(); j++) {
541  Eigen::Vector4f next_cog = new_cogs[j];
542  double distance = (next_cog - previous_cog).norm();
543  D[i * old_cogs.size() + j] = distance;
544  }
545  }
546  }
547 
548  void EuclideanClustering::removeDuplicatedIndices(
549  pcl::PointIndices::Ptr indices)
550  {
551  std::sort(indices->indices.begin(), indices->indices.end());
552  indices->indices.erase(
553  std::unique(indices->indices.begin(), indices->indices.end()),
554  indices->indices.end());
555  }
556 
557  void EuclideanClustering::computeCentroidsOfClusters(
558  Vector4fVector& ret,
559  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
560  std::vector<pcl::PointIndices> cluster_indices)
561  {
562  pcl::ExtractIndices<pcl::PointXYZ> extract;
563  extract.setInputCloud(cloud);
564  ret.resize(cluster_indices.size());
565  for (size_t i = 0; i < cluster_indices.size(); i++)
566  {
567  // build pointcloud
568  pcl::PointCloud<pcl::PointXYZ>::Ptr segmented_cloud (new pcl::PointCloud<pcl::PointXYZ>);
569  pcl::PointIndices::Ptr segmented_indices (new pcl::PointIndices);
570  for (size_t j = 0; j < cluster_indices[i].indices.size(); j++)
571  {
572  segmented_indices->indices.push_back(cluster_indices[i].indices[j]);
573  }
574  extract.setIndices(segmented_indices);
575  extract.filter(*segmented_cloud);
576  Eigen::Vector4f center;
577  pcl::compute3DCentroid(*segmented_cloud, center);
578  ret[i] = center;
579  }
580  }
581 
582 }
583 
586 
timer
void addDiagnosticInformation(const std::string &string_prefix, jsk_topic_tools::TimeAccumulator &accumulator, diagnostic_updater::DiagnosticStatusWrapper &stat)
void summary(unsigned char lvl, const std::string s)
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
std::vector< pcl::PointIndices::Ptr > convertToPCLPointIndices(const std::vector< PCLIndicesMsg > &cluster_indices)
D
size
void toPCL(const pcl_msgs::PointIndices &pi, pcl::PointIndices &pcl_pi)
unsigned int index
result
jsk_pcl_ros::EuclideanClusteringConfig Config
p
void add(const std::string &key, const T &val)
boost::mutex mutex_
cloud
PLUGINLIB_EXPORT_CLASS(jsk_pcl_ros::EuclideanClustering, nodelet::Nodelet)
double distance(const urdf::Pose &transform)
std_msgs::Header fromPCL(const pcl::PCLHeader &pcl_header)
std::vector< Eigen::Vector4f, Eigen::aligned_allocator< Eigen::Vector4f > > Vector4fVector


jsk_pcl_ros
Author(s): Yohei Kakiuchi
autogenerated on Mon May 3 2021 03:03:46