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,
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(),
62 std::fill(sampled_to_original_indices.begin(),
63 sampled_to_original_indices.end(),
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)) {
70 int index = voxel.getCentroidIndex(p);
74 original_to_sampled_indices[i] = index;
75 sampled_to_original_indices[index].push_back(i);
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) {
86 clustered_indices.clear();
89 pcl::PointCloud<pcl::PointXYZ>::Ptr preprocessed_cloud(
90 new pcl::PointCloud<pcl::PointXYZ>);
92 downsample_cloud(cloud,
94 downsample_to_original_indices_,
95 original_to_downsample_indices_,
99 preprocessed_cloud = cloud;
102 if (preprocessed_cloud->points.size() == 0) {
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) {
111 index = original_to_downsample_indices_[original_index];
113 index = original_index;
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);
124 removeDuplicatedIndices(nonnan_indices);
126 pcl::PointIndices result_point_indices;
127 if (nonnan_indices->indices.size() > 0) {
129 pcl::PointCloud<pcl::PointXYZ>::Ptr filtered_cloud(
new pcl::PointCloud<pcl::PointXYZ>);
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);
139 if (filtered_cloud->points.size() > 0) {
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> > ();
145 pcl::KdTree<pcl::PointXYZ>::Ptr tree (
new pcl::KdTreeFLANN<pcl::PointXYZ>);
146 tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointXYZ> > ();
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);
156 std::vector<pcl::PointIndices> output_indices;
159 impl.extract(output_indices);
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());
169 removeDuplicatedIndices(tmp_indices);
170 output_indices[i] = *tmp_indices;
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]];
179 output_indices[i] = tmp_indices;
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);
192 case jsk_pcl_ros::EuclideanClustering_MaxSize: {
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();
202 examine_indices.push_back(index);
206 for (
int index : examine_indices) {
207 result_point_indices.indices = output_indices.at(
index).indices;
208 clustered_indices.push_back(result_point_indices);
211 clustered_indices.push_back(result_point_indices);
216 void EuclideanClustering::extract(
217 const sensor_msgs::PointCloud2ConstPtr &input)
219 vital_checker_->poke();
220 pcl::PointCloud<pcl::PointXYZ>::Ptr
cloud 221 (
new pcl::PointCloud<pcl::PointXYZ>);
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;
229 std::vector<pcl::PointIndices::Ptr> cluster_indices{whole_indices};
230 std::vector<pcl::PointIndices> clustered_indices;
231 clusteringClusterIndices(cloud,
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()) {
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);
256 computeCentroidsOfClusters(tmp_cogs, cloud, clustered_indices);
259 for (
size_t i = 0; i < clustered_indices.size(); i++) {
260 #if ROS_VERSION_MINIMUM(1, 10, 0) 262 result.cluster_indices[i].header
266 result.cluster_indices[i].header = clustered_indices[i].header;
268 result.cluster_indices[i].indices = clustered_indices[i].indices;
271 result_pub_.publish(result);
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);
278 diagnostic_updater_->update();
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>);
289 std::vector<pcl::PointIndices::Ptr> cluster_indices =
291 std::vector<pcl::PointIndices> clustered_indices;
292 clusteringClusterIndices(cloud,
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;
302 for (
size_t i = 0; i < clustered_indices.size(); i++) {
303 #if ROS_VERSION_MINIMUM(1, 10, 0) 305 result.cluster_indices[i].header
309 result.cluster_indices[i].header = clustered_indices[i].header;
311 result.cluster_indices[i].indices = clustered_indices[i].indices;
314 result_pub_.publish(result);
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);
321 diagnostic_updater_->update();
324 bool EuclideanClustering::serviceCallback(
325 jsk_recognition_msgs::EuclideanSegment::Request &
req,
326 jsk_recognition_msgs::EuclideanSegment::Response &
res)
328 pcl::PointCloud<pcl::PointXYZ>::Ptr
cloud (
new pcl::PointCloud<pcl::PointXYZ>);
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> > ();
335 pcl::KdTree<pcl::PointXYZ>::Ptr tree (
new pcl::KdTreeFLANN<pcl::PointXYZ>);
336 tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointXYZ> > ();
339 vector<pcl::PointIndices> cluster_indices;
342 if ( req.tolerance < 0) {
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);
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);
358 pcl::ExtractIndices<pcl::PCLPointCloud2>
ex;
359 ex.setInputCloud(pcl_cloud);
361 pcl::ExtractIndices<sensor_msgs::PointCloud2>
ex;
362 ex.setInputCloud ( boost::make_shared< sensor_msgs::PointCloud2 > (req.input) );
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 );
372 ex.filter ( res.output[i] );
378 void EuclideanClustering::onInit()
380 DiagnosticNodelet::onInit();
382 pnh_->param(
"multi", multi_,
false);
383 pnh_->param(
"approximate_sync", approximate_sync_,
false);
384 pnh_->param(
"queue_size", queue_size_, 20);
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);
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);
405 void EuclideanClustering::subscribe()
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));
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));
423 sub_input_ = pnh_->subscribe(
"input", 1, &EuclideanClustering::extract,
this);
427 void EuclideanClustering::unsubscribe()
430 sub_cluster_indices_.unsubscribe();
431 sub_point_cloud_.unsubscribe();
433 sub_input_.shutdown();
437 void EuclideanClustering::updateDiagnostic(
440 if (vital_checker_->isAlive()) {
442 diagnostic_msgs::DiagnosticStatus::OK,
443 "EuclideanSegmentation running");
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_);
457 stat.
add(
"Leaf size", leaf_size_);
460 DiagnosticNodelet::updateDiagnostic(stat);
463 void EuclideanClustering::configCallback (
Config &config, uint32_t level)
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;
472 downsample_ = config.downsample_enable;
473 leaf_size_ = config.leaf_size;
476 std::vector<pcl::PointIndices> EuclideanClustering::pivotClusterIndices(
477 std::vector<int>& pivot_table,
478 std::vector<pcl::PointIndices>& cluster_indices)
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]];
485 return new_cluster_indices;
487 std::vector<int> EuclideanClustering::buildLabelTrackingPivotTable(
489 double label_tracking_tolerance)
491 std::vector<int> pivot_table;
493 pivot_table.resize(cogs.size());
494 for (
size_t i = 0; i < pivot_table.size(); i++)
496 for (
size_t pivot_counter = 0; pivot_counter < pivot_table.size();
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++)
504 for (
size_t j = 0; j < new_cogs.size(); j++)
506 double distance = D[i * cogs.size() + j];
508 if (distance < minimum_distance)
510 minimum_distance = distance;
511 minimum_previous_index = i;
512 minimum_next_index = j;
516 if (minimum_distance > label_tracking_tolerance)
520 std::vector<int> dummy;
523 pivot_table[minimum_previous_index] = minimum_next_index;
525 for (
size_t j = 0; j < new_cogs.size(); j++)
527 D[minimum_previous_index * cogs.size() + j] = DBL_MAX;
533 void EuclideanClustering::computeDistanceMatrix(
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;
548 void EuclideanClustering::removeDuplicatedIndices(
549 pcl::PointIndices::Ptr indices)
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());
557 void EuclideanClustering::computeCentroidsOfClusters(
559 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
560 std::vector<pcl::PointIndices> cluster_indices)
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++)
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++)
572 segmented_indices->indices.push_back(cluster_indices[i].indices[j]);
574 extract.setIndices(segmented_indices);
575 extract.filter(*segmented_cloud);
576 Eigen::Vector4f center;
577 pcl::compute3DCentroid(*segmented_cloud, center);
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)
void toPCL(const pcl_msgs::PointIndices &pi, pcl::PointIndices &pcl_pi)
jsk_pcl_ros::EuclideanClusteringConfig Config
void add(const std::string &key, const T &val)
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