sac_inc_ground_removal_standalone.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008 Radu Bogdan Rusu <rusu -=- cs.tum.edu>
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  *
27  * $Id$
28  *
29  */
30 
42 // ROS core
43 #include <ros/ros.h>
44 // ROS messages
45 #include <Eigen/QR>
46 #include <Eigen/Eigenvalues>
47 // Sample Consensus
48 #include <sac.h>
49 #include <ransac.h>
50 #include <sac_model_line.h>
51 
52 #include <tf/transform_listener.h>
53 #include "tf/message_filter.h"
55 
56 #include <sys/time.h>
57 
58 #include <boost/thread.hpp>
59 
60 #include <pcl_ros/transforms.h>
61 
62 using namespace std;
63 
65 {
66  protected:
68 
69  public:
70 
71  // ROS messages
72  sample_consensus::PointCloud laser_cloud_, cloud_, cloud_noground_;
73 
75  geometry_msgs::PointStamped viewpoint_cloud_;
78 
79  // Parameters
80  double z_threshold_, ground_slope_threshold_;
81  int sac_min_points_per_model_, sac_max_iterations_;
85  std::string robot_footprint_frame_, laser_tilt_mount_frame_;
86 
88 
90  IncGroundRemoval (ros::NodeHandle& anode) : node_ (anode)
91  {
92  node_.param ("z_threshold", z_threshold_, 0.1); // 10cm threshold for ground removal
93  node_.param ("ground_slope_threshold", ground_slope_threshold_, 0.0); // 0% slope threshold for ground removal
94  node_.param ("sac_distance_threshold", sac_distance_threshold_, 0.03); // 3 cm threshold
95  node_.param ("sac_fitting_distance_threshold", sac_fitting_distance_threshold_, 0.015); // 1.5 cm threshold
96 
97  node_.param ("planar_refine", planar_refine_, 1); // enable a final planar refinement step?
98  node_.param ("sac_min_points_per_model", sac_min_points_per_model_, 6); // 6 points minimum per line
99  node_.param ("sac_max_iterations", sac_max_iterations_, 200); // maximum 200 iterations
100  node_.param ("robot_footprint_frame", robot_footprint_frame_, std::string("base_footprint"));
101  node_.param ("laser_tilt_mount_frame", laser_tilt_mount_frame_, std::string("laser_tilt_mount_link"));
102 
103  string cloud_topic ("tilt_laser_cloud_filtered");
104 
105  bool topic_found = false;
106  std::vector<ros::master::TopicInfo> t_list;
107  ros::master::getTopics (t_list);
108  for (vector<ros::master::TopicInfo>::iterator it = t_list.begin (); it != t_list.end (); it++)
109  {
110  if (it->name == cloud_topic)
111  {
112  topic_found = true;
113  break;
114  }
115  }
116  if (!topic_found)
117  ROS_WARN ("Trying to subscribe to %s, but the topic doesn't exist!", cloud_topic.c_str ());
118 
119  ros::NodeHandle public_node;
120 
121  //subscribe (cloud_topic.c_str (), laser_cloud_, &IncGroundRemoval::cloud_cb, 1);
122  cloud_subscriber_ = new message_filters::Subscriber<sensor_msgs::PointCloud2>(public_node,cloud_topic,50);
123  cloud_notifier_ = new tf::MessageFilter<sensor_msgs::PointCloud2>(*cloud_subscriber_,tf_,"odom_combined",50);
124  cloud_notifier_->registerCallback(boost::bind(&IncGroundRemoval::cloud_cb,this,_1));
125 
126 // cloud_notifier_ = new tf::MessageNotifier<sample_consensus::PointCloud> (&tf_, node_,
127 // boost::bind (&IncGroundRemoval::cloud_cb, this, _1), cloud_topic, "odom_combined", 50);
128 
129  cloud_publisher_ = public_node.advertise<sensor_msgs::PointCloud2> ("cloud_ground_filtered", 1);
130  }
131 
133  virtual ~IncGroundRemoval () { delete cloud_notifier_; }
134 
136  void
138  {
139  node_.getParam ("z_threshold", z_threshold_);
140  node_.getParam ("ground_slope_threshold", ground_slope_threshold_);
141  node_.getParam ("sac_fitting_distance_threshold", sac_fitting_distance_threshold_);
142  node_.getParam ("sac_distance_threshold", sac_distance_threshold_);
143  }
144 
146 
151  bool
152  fitSACLine (sample_consensus::PointCloud *points, vector<int> *indices, vector<int> &inliers)
153  {
154  if ((int)indices->size () < sac_min_points_per_model_)
155  return (false);
156 
157  // Create and initialize the SAC model
159  sample_consensus::SAC *sac = new sample_consensus::RANSAC (model, sac_fitting_distance_threshold_);
160  sac->setMaxIterations (sac_max_iterations_);
161  sac->setProbability (0.99);
162 
163  model->setDataSet (points, *indices);
164 
165  vector<double> line_coeff;
166  // Search for the best model
167  if (sac->computeModel (0))
168  {
169  // Obtain the inliers and the planar model coefficients
170  if ((int)sac->getInliers ().size () < sac_min_points_per_model_)
171  return (false);
172  //inliers = sac->getInliers ();
173 
174  sac->computeCoefficients (line_coeff); // Compute the model coefficients
175  sac->refineCoefficients (line_coeff); // Refine them using least-squares
176  model->selectWithinDistance (line_coeff, sac_distance_threshold_, inliers);
177 
178  // Project the inliers onto the model
179  //model->projectPointsInPlace (sac->getInliers (), coeff);
180  }
181  else
182  return (false);
183 
184  delete sac;
185  delete model;
186  return (true);
187  }
188 
190 
195  inline void
196  flipNormalTowardsViewpoint (Eigen::Vector4d &normal, const pcl::PointXYZ &point, const geometry_msgs::PointStamped &viewpoint)
197  {
198  // See if we need to flip any plane normals
199  float vp_m[3];
200  vp_m[0] = viewpoint.point.x - point.x;
201  vp_m[1] = viewpoint.point.y - point.y;
202  vp_m[2] = viewpoint.point.z - point.z;
203 
204  // Dot product between the (viewpoint - point) and the plane normal
205  double cos_theta = (vp_m[0] * normal (0) + vp_m[1] * normal (1) + vp_m[2] * normal (2));
206 
207  // Flip the plane normal
208  if (cos_theta < 0)
209  {
210  for (int d = 0; d < 3; d++)
211  normal (d) *= -1;
212  // Hessian form (D = nc . p_plane (centroid here) + p)
213  normal (3) = -1 * (normal (0) * point.x + normal (1) * point.y + normal (2) * point.z);
214  }
215  }
216 
218 
223  inline void
224  computeCentroid (const sample_consensus::PointCloud &points, const std::vector<int> &indices, pcl::PointXYZ &centroid)
225  {
226  centroid.x = centroid.y = centroid.z = 0;
227  // For each point in the cloud
228  for (unsigned int i = 0; i < indices.size (); i++)
229  {
230  centroid.x += points.points.at (indices.at (i)).x;
231  centroid.y += points.points.at (indices.at (i)).y;
232  centroid.z += points.points.at (indices.at (i)).z;
233  }
234 
235  centroid.x /= indices.size ();
236  centroid.y /= indices.size ();
237  centroid.z /= indices.size ();
238  }
239 
241 
249  inline void
250  computeCovarianceMatrix (const sample_consensus::PointCloud &points, const std::vector<int> &indices, Eigen::Matrix3d &covariance_matrix, pcl::PointXYZ &centroid)
251  {
252  computeCentroid (points, indices, centroid);
253 
254  // Initialize to 0
255  covariance_matrix = Eigen::Matrix3d::Zero ();
256 
257  for (unsigned int j = 0; j < indices.size (); j++)
258  {
259  covariance_matrix (0, 0) += (points.points[indices.at (j)].x - centroid.x) * (points.points[indices.at (j)].x - centroid.x);
260  covariance_matrix (0, 1) += (points.points[indices.at (j)].x - centroid.x) * (points.points[indices.at (j)].y - centroid.y);
261  covariance_matrix (0, 2) += (points.points[indices.at (j)].x - centroid.x) * (points.points[indices.at (j)].z - centroid.z);
262 
263  covariance_matrix (1, 0) += (points.points[indices.at (j)].y - centroid.y) * (points.points[indices.at (j)].x - centroid.x);
264  covariance_matrix (1, 1) += (points.points[indices.at (j)].y - centroid.y) * (points.points[indices.at (j)].y - centroid.y);
265  covariance_matrix (1, 2) += (points.points[indices.at (j)].y - centroid.y) * (points.points[indices.at (j)].z - centroid.z);
266 
267  covariance_matrix (2, 0) += (points.points[indices.at (j)].z - centroid.z) * (points.points[indices.at (j)].x - centroid.x);
268  covariance_matrix (2, 1) += (points.points[indices.at (j)].z - centroid.z) * (points.points[indices.at (j)].y - centroid.y);
269  covariance_matrix (2, 2) += (points.points[indices.at (j)].z - centroid.z) * (points.points[indices.at (j)].z - centroid.z);
270  }
271  }
272 
274 
284  void
285  computePointNormal (const sample_consensus::PointCloud &points, const std::vector<int> &indices, Eigen::Vector4d &plane_parameters, double &curvature)
286  {
287  pcl::PointXYZ centroid;
288  // Compute the 3x3 covariance matrix
289  Eigen::Matrix3d covariance_matrix;
290  computeCovarianceMatrix (points, indices, covariance_matrix, centroid);
291 
292  // Extract the eigenvalues and eigenvectors
293  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> ei_symm (covariance_matrix);
294  Eigen::Vector3d eigen_values = ei_symm.eigenvalues ();
295  Eigen::Matrix3d eigen_vectors = ei_symm.eigenvectors ();
296 
297  // Normalize the surface normal (eigenvector corresponding to the smallest eigenvalue)
298  // Note: Remember to take care of the eigen_vectors ordering
299  double norm = sqrt ( eigen_vectors (0, 0) * eigen_vectors (0, 0) +
300  eigen_vectors (1, 0) * eigen_vectors (1, 0) +
301  eigen_vectors (2, 0) * eigen_vectors (2, 0));
302  plane_parameters (0) = eigen_vectors (0, 0) / norm;
303  plane_parameters (1) = eigen_vectors (1, 0) / norm;
304  plane_parameters (2) = eigen_vectors (2, 0) / norm;
305 
306  // Hessian form (D = nc . p_plane (centroid here) + p)
307  plane_parameters (3) = -1 * (plane_parameters (0) * centroid.x + plane_parameters (1) * centroid.y + plane_parameters (2) * centroid.z);
308 
309  // Compute the curvature surface change
310  curvature = fabs ( eigen_values (0) / (eigen_values (0) + eigen_values (1) + eigen_values (2)) );
311  }
312 
314  // Callback
315  void cloud_cb (const sensor_msgs::PointCloud2::ConstPtr& msg)
316  {
317  pcl::fromROSMsg(*msg,laser_cloud_);
318  //check to see if the point cloud is empty
319  if(laser_cloud_.points.empty()){
320  ROS_DEBUG("Received an empty point cloud");
321  cloud_publisher_.publish(msg);
322  return;
323  }
324 
325  try{
326  pcl_ros::transformPointCloud("odom_combined", laser_cloud_, cloud_, tf_);
327  }
328  catch(tf::TransformException &ex){
329  ROS_ERROR("Can't transform cloud for ground plane detection");
330  return;
331  }
332 
333  ROS_DEBUG ("Received %d data points.", (int)cloud_.points.size ());
334  if (cloud_.points.size () == 0)
335  return;
336 
337  //updateParametersFromServer ();
338  // Copy the header
339  cloud_noground_.header = cloud_.header;
340 
341  timeval t1, t2;
342  gettimeofday (&t1, NULL);
343 
344  // Get the cloud viewpoint
345  getCloudViewPoint (cloud_.header.frame_id, viewpoint_cloud_, &tf_);
346 
347  // Transform z_threshold_ from the parameter parameter frame (parameter_frame_) into the point cloud frame
348  std_msgs::Header header = pcl_conversions::fromPCL(cloud_.header);
349  double z_threshold_cloud = transformDoubleValueTF (z_threshold_, robot_footprint_frame_, cloud_.header.frame_id, header.stamp, &tf_);
350 
351  // Select points whose Z dimension is close to the ground (0,0,0 in base_footprint) or under a gentle slope (allowing for pitch/roll error)
352  vector<int> possible_ground_indices (cloud_.points.size ());
353  vector<int> all_indices (cloud_.points.size ());
354  int nr_p = 0;
355  for (unsigned int cp = 0; cp < cloud_.points.size (); cp++)
356  {
357  all_indices[cp] = cp;
358  if (fabs (cloud_.points[cp].z) < z_threshold_cloud || // max height for ground
359  cloud_.points[cp].z*cloud_.points[cp].z < ground_slope_threshold_ * (cloud_.points[cp].x*cloud_.points[cp].x + cloud_.points[cp].y*cloud_.points[cp].y)) // max slope for ground
360  {
361  possible_ground_indices[nr_p] = cp;
362  nr_p++;
363  }
364  }
365  possible_ground_indices.resize (nr_p);
366 
367  ROS_DEBUG ("Number of possible ground indices: %d.", (int)possible_ground_indices.size ());
368 
369  vector<int> ground_inliers;
370 
371  // Find the dominant plane in the space of possible ground indices
372  fitSACLine (&cloud_, &possible_ground_indices, ground_inliers);
373 
374 
375  if (ground_inliers.size () == 0){
376  ROS_DEBUG ("Couldn't fit a model to the scan.");
377  //if we can't fit a line model to the scan, we have to assume all the possible ground inliers are on the ground
378  ground_inliers = possible_ground_indices;
379  }
380 
381  ROS_DEBUG ("Total number of ground inliers before refinement: %d.", (int)ground_inliers.size ());
382 
383  // Do we attempt to do a planar refinement to remove points "below" the plane model found ?
384  if (planar_refine_ > 0)
385  {
386  // Get the remaining point indices
387  vector<int> remaining_possible_ground_indices;
388  sort (all_indices.begin (), all_indices.end ());
389  sort (ground_inliers.begin (), ground_inliers.end ());
390  set_difference (all_indices.begin (), all_indices.end (), ground_inliers.begin (), ground_inliers.end (),
391  inserter (remaining_possible_ground_indices, remaining_possible_ground_indices.begin ()));
392 
393  // Estimate the plane from the line inliers
394  Eigen::Vector4d plane_parameters;
395  double curvature;
396  computePointNormal (cloud_, ground_inliers, plane_parameters, curvature);
397 
398  //make sure that there are inliers to refine
399  if (!ground_inliers.empty ())
400  {
401  flipNormalTowardsViewpoint (plane_parameters, cloud_.points.at (ground_inliers[0]), viewpoint_cloud_);
402 
403  // Compute the distance from the remaining points to the model plane, and add to the inliers list if they are below
404  for (unsigned int i = 0; i < remaining_possible_ground_indices.size (); i++)
405  {
406  double distance_to_ground = pointToPlaneDistanceSigned (cloud_.points.at (remaining_possible_ground_indices[i]), plane_parameters);
407  if (distance_to_ground >= 1e-6){
408  continue;
409  }
410  ground_inliers.push_back (remaining_possible_ground_indices[i]);
411  }
412  }
413  }
414  ROS_DEBUG ("Total number of ground inliers after refinement: %d.", (int)ground_inliers.size ());
415 
416  // Get all the non-ground point indices
417  vector<int> remaining_indices;
418  sort (ground_inliers.begin (), ground_inliers.end ());
419  sort (all_indices.begin(), all_indices.end());
420  set_difference (all_indices.begin (), all_indices.end (), ground_inliers.begin (), ground_inliers.end (),
421  inserter (remaining_indices, remaining_indices.begin ()));
422 
423  // Prepare new arrays
424  int nr_remaining_pts = remaining_indices.size ();
425  cloud_noground_.points.resize (nr_remaining_pts);
426 
427  for (unsigned int i = 0; i < remaining_indices.size (); i++)
428  {
429  cloud_noground_.points[i].x = cloud_.points.at (remaining_indices[i]).x;
430  cloud_noground_.points[i].y = cloud_.points.at (remaining_indices[i]).y;
431  cloud_noground_.points[i].z = cloud_.points.at (remaining_indices[i]).z;
432  }
433 
434  gettimeofday (&t2, NULL);
435  double time_spent = t2.tv_sec + (double)t2.tv_usec / 1000000.0 - (t1.tv_sec + (double)t1.tv_usec / 1000000.0);
436  ROS_DEBUG ("Number of points found on ground plane: %d ; remaining: %d (%g seconds).", (int)ground_inliers.size (),
437  (int)remaining_indices.size (), time_spent);
438  sensor_msgs::PointCloud2 out;
439  pcl::toROSMsg(cloud_noground_, out);
440  cloud_publisher_.publish (out);
441  }
442 
443 
445 
449  inline double
450  pointToPlaneDistanceSigned (const pcl::PointXYZ &p, const Eigen::Vector4d &plane_coefficients)
451  {
452  return ( plane_coefficients (0) * p.x + plane_coefficients (1) * p.y + plane_coefficients (2) * p.z + plane_coefficients (3) );
453  }
454 
456 
461  void
462  getCloudViewPoint (string cloud_frame, geometry_msgs::PointStamped &viewpoint_cloud, tf::TransformListener *tf)
463  {
464  // Figure out the viewpoint value in the point cloud frame
465  geometry_msgs::PointStamped viewpoint_laser;
466  viewpoint_laser.header.frame_id = laser_tilt_mount_frame_;
467  // Set the viewpoint in the laser coordinate system to 0, 0, 0
468  viewpoint_laser.point.x = viewpoint_laser.point.y = viewpoint_laser.point.z = 0.0;
469 
470  try
471  {
472  tf->transformPoint (cloud_frame, viewpoint_laser, viewpoint_cloud);
473  ROS_DEBUG ("Cloud view point in frame %s is: %g, %g, %g.", cloud_frame.c_str (),
474  viewpoint_cloud.point.x, viewpoint_cloud.point.y, viewpoint_cloud.point.z);
475  }
477  {
478  ROS_WARN ("Could not transform a point from frame %s to frame %s!", viewpoint_laser.header.frame_id.c_str (), cloud_frame.c_str ());
479  // Default to 0.05, 0, 0.942768
480  viewpoint_cloud.point.x = 0.05; viewpoint_cloud.point.y = 0.0; viewpoint_cloud.point.z = 0.942768;
481  }
482  catch(tf::TransformException &ex){
483  ROS_ERROR("Can't transform viewpoint for ground plan detection");
484  viewpoint_cloud.point.x = 0.05; viewpoint_cloud.point.y = 0.0; viewpoint_cloud.point.z = 0.942768;
485  }
486  }
487 
489 
495  inline void
496  transformPoint (tf::TransformListener *tf, const std::string &target_frame,
497  const tf::Stamped< pcl::PointXYZ > &stamped_in, tf::Stamped< pcl::PointXYZ > &stamped_out)
498  {
500  tmp.stamp_ = stamped_in.stamp_;
501  tmp.frame_id_ = stamped_in.frame_id_;
502  tmp[0] = stamped_in.x;
503  tmp[1] = stamped_in.y;
504  tmp[2] = stamped_in.z;
505 
506  try{
507  tf->transformPoint (target_frame, tmp, tmp);
508  }
509  catch(tf::TransformException &ex){
510  ROS_ERROR("Can't transform cloud for ground plane detection");
511  return;
512  }
513 
514  stamped_out.stamp_ = tmp.stamp_;
515  stamped_out.frame_id_ = tmp.frame_id_;
516  stamped_out.x = tmp[0];
517  stamped_out.y = tmp[1];
518  stamped_out.z = tmp[2];
519  }
520 
522 
529  inline double
530  transformDoubleValueTF (double val, std::string src_frame, std::string tgt_frame, ros::Time stamp, tf::TransformListener *tf)
531  {
532  pcl::PointXYZ temp;
533  temp.x = temp.y = 0;
534  temp.z = val;
535  tf::Stamped<pcl::PointXYZ> temp_stamped (temp, stamp, src_frame);
536  transformPoint (tf, tgt_frame, temp_stamped, temp_stamped);
537  return (temp_stamped.z);
538  }
539 
540 };
541 
542 /* ---[ */
543 int
544  main (int argc, char** argv)
545 {
546  ros::init (argc, argv, "sac_ground_removal");
547 
548  ros::NodeHandle ros_node ("~");
549 
550  // For efficiency considerations please make sure the input sample_consensus::PointCloud is in a frame with Z point upwards
551  IncGroundRemoval p (ros_node);
552  ros::spin ();
553 
554  return (0);
555 }
556 /* ]--- */
557 
d
void cloud_cb(const sensor_msgs::PointCloud2::ConstPtr &msg)
pcl::PointCloud< pcl::PointXYZ > PointCloud
Definition: sac_model.h:43
void publish(const boost::shared_ptr< M > &message) const
virtual void computeCoefficients(std::vector< double > &coefficients)
Compute the coefficients of the model and return them.
Definition: sac.h:105
void getCloudViewPoint(string cloud_frame, geometry_msgs::PointStamped &viewpoint_cloud, tf::TransformListener *tf)
Get the view point from where the scans were taken in the incoming sample_consensus::PointCloud messa...
void computePointNormal(const sample_consensus::PointCloud &points, const std::vector< int > &indices, Eigen::Vector4d &plane_parameters, double &curvature)
Compute the Least-Squares plane fit for a given set of points, using their indices, and return the estimated plane parameters together with the surface curvature.
int main(int argc, char **argv)
virtual void setProbability(double probability)
Set the desired probability of choosing at least one sample free from outliers.
Definition: sac.h:93
void transformPoint(tf::TransformListener *tf, const std::string &target_frame, const tf::Stamped< pcl::PointXYZ > &stamped_in, tf::Stamped< pcl::PointXYZ > &stamped_out)
Transform a given point from its current frame to a given target frame.
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void computeCovarianceMatrix(const sample_consensus::PointCloud &points, const std::vector< int > &indices, Eigen::Matrix3d &covariance_matrix, pcl::PointXYZ &centroid)
Compute the 3x3 covariance matrix of a given set of points using their indices. The result is returne...
ROSCPP_DECL bool getTopics(V_TopicInfo &topics)
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
void transformPoint(const std::string &target_frame, const geometry_msgs::PointStamped &stamped_in, geometry_msgs::PointStamped &stamped_out) const
A Sample Consensus Model class for 3D line segmentation.
TFSIMD_FORCE_INLINE const tfScalar & y() const
#define ROS_WARN(...)
tf::MessageFilter< sensor_msgs::PointCloud2 > * cloud_notifier_
ROSCPP_DECL void spin(Spinner &spinner)
void fromPCL(const pcl::uint64_t &pcl_stamp, ros::Time &stamp)
virtual void setMaxIterations(int max_iterations)
Set the maximum number of iterations.
Definition: sac.h:83
bool fitSACLine(sample_consensus::PointCloud *points, vector< int > *indices, vector< int > &inliers)
Find a line model in a point cloud given via a set of point indices with SAmple Consensus methods...
bool param(const std::string &param_name, T &param_val, const T &default_val) const
double transformDoubleValueTF(double val, std::string src_frame, std::string tgt_frame, ros::Time stamp, tf::TransformListener *tf)
Transform a value from a source frame to a target frame at a certain moment in time with TF...
message_filters::Subscriber< sensor_msgs::PointCloud2 > * cloud_subscriber_
virtual bool computeModel(int debug=0)=0
Compute the actual model. Pure virtual.
TFSIMD_FORCE_INLINE const tfScalar & x() const
void flipNormalTowardsViewpoint(Eigen::Vector4d &normal, const pcl::PointXYZ &point, const geometry_msgs::PointStamped &viewpoint)
Flip (in place) the estimated normal of a point towards a given viewpoint.
void computeCentroid(const sample_consensus::PointCloud &points, const std::vector< int > &indices, pcl::PointXYZ &centroid)
Compute the centroid of a set of points using their indices and return it as a Point32 message...
virtual void refineCoefficients(std::vector< double > &refined_coefficients)
Use Least-Squares optimizations to refine the coefficients of the model, and return them...
Definition: sac.h:116
IncGroundRemoval(ros::NodeHandle &anode)
TFSIMD_FORCE_INLINE const tfScalar & z() const
virtual std::vector< int > getInliers()
Get a list of the model inliers, found after computeModel ()
Definition: sac.h:128
ros::Time stamp_
sample_consensus::PointCloud laser_cloud_
std::string frame_id_
void transformPointCloud(const pcl::PointCloud< PointT > &cloud_in, pcl::PointCloud< PointT > &cloud_out, const tf::Transform &transform)
bool getParam(const std::string &key, std::string &s) const
void toROSMsg(const sensor_msgs::PointCloud2 &cloud, sensor_msgs::Image &image)
#define ROS_ERROR(...)
double pointToPlaneDistanceSigned(const pcl::PointXYZ &p, const Eigen::Vector4d &plane_coefficients)
Get the distance from a point to a plane (signed) defined by ax+by+cz+d=0.
virtual void selectWithinDistance(const std::vector< double > &model_coefficients, double threshold, std::vector< int > &inliers)
Select all the points which respect the given model coefficients as inliers.
geometry_msgs::PointStamped viewpoint_cloud_
Connection registerCallback(const C &callback)
#define ROS_DEBUG(...)
void setDataSet(PointCloud *cloud)
Set the dataset.
Definition: sac_model.h:129


semantic_point_annotator
Author(s): Radu Bogdan Rusu
autogenerated on Mon Jun 10 2019 14:29:03