Username
Username

Reputation: 59

How to extract a set of points in a point cloud data using PCL?

I have a point cloud data, where by clicking a point, I want to extract points surrounding the clicked point within a radius. I want to also push the extracted points into a new cloud. Using Pointpickingevent, I am able to click one point and push it into the cloud. How do I extract a set of points, say points surrounding 0.02cm radius from the clicked point and push them into a new cloud?

Upvotes: 3

Views: 7161

Answers (2)

R.Falque
R.Falque

Reputation: 944

In order to be able to pick a point you can use PointPickingEvent similarly to this answer.

The Class declaration in your .h,

class PCLViewer : public QMainWindow
{
  Q_OBJECT

public:
  explicit PCLViewer (QWidget *parent = 0);
  ~PCLViewer ();
    void pointPickCallback (const pcl::visualization::PointPickingEvent& event, void*);

public slots:

protected:
  boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer;
  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
  pcl::PointXYZ src_point_;
  bool src_point_selected_;

private:
  Ui::PCLViewer *ui;

};

In your .cpp,

PCLViewer::PCLViewer (QWidget *parent) :
  QMainWindow (parent),
  ui (new Ui::PCLViewer)
{
    ui->setupUi (this);

    [...]

    viewer.reset (new pcl::visualization::PCLVisualizer ("viewer", false));
    viewer->registerPointPickingCallback (&PCLViewer::pointPickCallback, *this);

    [...]
}

and the additional function,

void
PCLViewer::pointPickCallback (const pcl::visualization::PointPickingEvent& event, void*)
{
  // Check to see if we got a valid point. Early exit.
  int idx = event.getPointIndex ();
  if (idx == -1)
    return;

  // Get the point that was picked
  event.getPoint (src_point_.x, src_point_.y, src_point_.z);
  PCL_INFO ("Src Window: Clicked point %d with X:%f Y:%f Z:%f\n", idx, src_point_.x, src_point_.y, src_point_.z);
  src_point_selected_ = true;
}

There is a more detailed example of the utilisation of it in the manual registration app: pcl/apps/src/manual_registration/manual_registration.cpp pcl/apps/include/pcl/apps/manual_registration.h

Upvotes: 1

Albert Pumarola
Albert Pumarola

Reputation: 656

Given a point cloud:

pcl::PointCloud<pcl::PointXYZ>::Ptr cloud

A Kdtree is then generated to perform an efficient range search:

pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
kdtree.setInputCloud (cloud);

Then, given a point and a radius:

pcl::PointXYZ searchPoint(1,2,3);
float radius = 4;

You can get all the points that are at a distance radius from the point searchPoint:

std::vector<int> pointIdxRadiusSearch; //to store index of surrounding points 
std::vector<float> pointRadiusSquaredDistance; // to store distance to surrounding points

if ( kdtree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0 )
{
    for (size_t i = 0; i < pointIdxRadiusSearch.size (); ++i)
        std::cout << "    "  <<   cloud->points[ pointIdxRadiusSearch[i] ].x 
                << " " << cloud->points[ pointIdxRadiusSearch[i] ].y 
                << " " << cloud->points[ pointIdxRadiusSearch[i] ].z 
                << " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;
}

You can print all the surrounding points and their distance to the searchPoint to check the code functional correctness.

Finally, create a cloud with the obtained points:

pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster (new pcl::PointCloud<pcl::PointXYZ>);
for (size_t i = 0; i < pointIdxRadiusSearch.size (); ++i)
    cloud_cluster->points.push_back(cloud->points[ pointIdxRadiusSearch[i] ]);
cloud_cluster->width = cloud_cluster->points.size ();
cloud_cluster->height = 1;
cloud_cluster->is_dense = true;

Upvotes: 3

Related Questions