File: euclidean_clustering.cpp

package info (click to toggle)
pcl 1.15.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 143,128 kB
  • sloc: cpp: 520,234; xml: 28,792; ansic: 8,212; python: 334; lisp: 93; sh: 49; makefile: 30
file content (131 lines) | stat: -rw-r--r-- 5,936 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <pcl/apps/cloud_composer/tools/euclidean_clustering.h>
#include <pcl/apps/cloud_composer/items/cloud_item.h>

#include <pcl/memory.h>  // for pcl::make_shared
#include <pcl/point_types.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/kdtree/kdtree.h>
#include <pcl/segmentation/extract_clusters.h>

Q_PLUGIN_METADATA(IID "cloud_composer.ToolFactory/1.0")

pcl::cloud_composer::EuclideanClusteringTool::EuclideanClusteringTool (PropertiesModel* parameter_model, QObject* parent)
  : SplitItemTool (parameter_model, parent)
{

}

QList <pcl::cloud_composer::CloudComposerItem*>
pcl::cloud_composer::EuclideanClusteringTool::performAction (ConstItemList input_data, PointTypeFlags::PointType)
{
  QList <CloudComposerItem*> output;
  const CloudComposerItem* input_item;
  // Check input data length
  if ( input_data.empty ())
  {
    qCritical () << "Empty input in Euclidean Clustering Tool!";
    return output;
  }
  if ( input_data.size () > 1)
  {
    qWarning () << "Input vector has more than one item in Euclidean Clustering!";
  }
  input_item = input_data.value (0);

  if (input_item->type () == CloudComposerItem::CLOUD_ITEM)
  {
    const CloudItem* cloud_item = dynamic_cast <const CloudItem*> (input_item);
    if ( cloud_item->isSanitized())
    {
      double cluster_tolerance = parameter_model_->getProperty ("Cluster Tolerance").toDouble();
      int min_cluster_size = parameter_model_->getProperty ("Min Cluster Size").toInt();
      int max_cluster_size = parameter_model_->getProperty ("Max Cluster Size").toInt();

      pcl::PCLPointCloud2::ConstPtr input_cloud = input_item->data (ItemDataRole::CLOUD_BLOB).value <pcl::PCLPointCloud2::ConstPtr> ();
      //Get the cloud in template form
      pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
      pcl::fromPCLPointCloud2 (*input_cloud, *cloud);

      //////////////// THE WORK - COMPUTING CLUSTERS ///////////////////
      // Creating the KdTree object for the search method of the extraction
      pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
      tree->setInputCloud (cloud);

      std::vector<pcl::PointIndices> cluster_indices;
      pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;
      ec.setClusterTolerance (cluster_tolerance); 
      ec.setMinClusterSize (min_cluster_size);
      ec.setMaxClusterSize (max_cluster_size);
      ec.setSearchMethod (tree);
      ec.setInputCloud (cloud);
      ec.extract (cluster_indices);
      //////////////////////////////////////////////////////////////////
      //Get copies of the original origin and orientation
      Eigen::Vector4f source_origin = input_item->data (ItemDataRole::ORIGIN).value<Eigen::Vector4f> ();
      Eigen::Quaternionf source_orientation =  input_item->data (ItemDataRole::ORIENTATION).value<Eigen::Quaternionf> ();
      //Vector to accumulate the extracted indices
      pcl::IndicesPtr extracted_indices (new pcl::Indices ());
      //Put found clusters into new cloud_items!
      qDebug () << "Found "<<cluster_indices.size ()<<" clusters!";
      int cluster_count = 0;
      pcl::ExtractIndices<pcl::PCLPointCloud2> filter;
      for (const auto& cluster : cluster_indices)
      {
        filter.setInputCloud (input_cloud);
        // It's annoying that I have to do this, but Euclidean returns a PointIndices struct
        pcl::PointIndices::ConstPtr indices_ptr = pcl::make_shared<pcl::PointIndices>(cluster);
        filter.setIndices (indices_ptr);
        extracted_indices->insert (extracted_indices->end (), cluster.indices.begin (), cluster.indices.end ());
        //This means remove the other points
        filter.setKeepOrganized (false);
        pcl::PCLPointCloud2::Ptr cloud_filtered (new pcl::PCLPointCloud2);
        filter.filter (*cloud_filtered);

        qDebug() << "Cluster has " << cloud_filtered->width << " data points.";
        CloudItem* cloud_item = new CloudItem (input_item->text ()+tr("-Clstr %1").arg(cluster_count)
                                              , cloud_filtered
                                              , source_origin
                                              , source_orientation);
        output.append (cloud_item);
        ++cluster_count;
      }
      //We copy input cloud over for special case that no clusters found, since ExtractIndices doesn't work for 0 length vectors
      pcl::PCLPointCloud2::Ptr remainder_cloud (new pcl::PCLPointCloud2(*input_cloud));
      if (!cluster_indices.empty ())
      {
        //make a cloud containing all the remaining points
        filter.setIndices (extracted_indices);
        filter.setNegative (true);
        filter.filter (*remainder_cloud);
      }
      qDebug() << "Cloud has " << remainder_cloud->width << " data points after clusters removed.";
      CloudItem* cloud_item = new CloudItem (input_item->text ()+ " unclustered"
                                              , remainder_cloud
                                              , source_origin
                                              , source_orientation);
      output.push_front (cloud_item);
    }
    else
      qCritical () << "Input item in Clustering is not SANITIZED!!!";
  }
  else
  {
    qCritical () << "Input item in Clustering is not a cloud!!!";
  }


  return output;
}

/////////////////// PARAMETER MODEL /////////////////////////////////
pcl::cloud_composer::PropertiesModel*
pcl::cloud_composer::EuclideanClusteringToolFactory::createToolParameterModel (QObject* parent)
{
  PropertiesModel* parameter_model = new PropertiesModel(parent);

  parameter_model->addProperty ("Cluster Tolerance", 0.02,  Qt::ItemIsEditable | Qt::ItemIsEnabled);
  parameter_model->addProperty ("Min Cluster Size", 100,  Qt::ItemIsEditable | Qt::ItemIsEnabled);
  parameter_model->addProperty ("Max Cluster Size", 25000,  Qt::ItemIsEditable | Qt::ItemIsEnabled);

  return parameter_model;
}