laser_pattern.cpp
Go to the documentation of this file.
1 /*
2  velo2cam_calibration - Automatic calibration algorithm for extrinsic parameters of a stereo camera and a velodyne
3  Copyright (C) 2017-2018 Jorge Beltran, Carlos Guindel
4 
5  This file is part of velo2cam_calibration.
6 
7  velo2cam_calibration is free software: you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation, either version 2 of the License, or
10  (at your option) any later version.
11 
12  velo2cam_calibration is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with velo2cam_calibration. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 /*
22  laser_pattern: Find the circle centers in the laser cloud
23 */
24 
25 #define PCL_NO_PRECOMPILE
26 
27 #include <ros/ros.h>
28 #include "ros/package.h"
29 #include <sensor_msgs/PointCloud2.h>
33 #include <pcl/ModelCoefficients.h>
34 #include <pcl/io/pcd_io.h>
35 #include <pcl/point_cloud.h>
36 #include <pcl/point_types.h>
37 #include <pcl/filters/filter.h>
38 #include <pcl/sample_consensus/method_types.h>
39 #include <pcl/sample_consensus/model_types.h>
40 #include <pcl/segmentation/sac_segmentation.h>
42 #include <pcl_msgs/PointIndices.h>
43 #include <pcl_msgs/ModelCoefficients.h>
44 #include <pcl/common/geometry.h>
45 #include <pcl/common/eigen.h>
46 #include <pcl/common/transforms.h>
47 #include <pcl/filters/passthrough.h>
48 #include <pcl/filters/impl/passthrough.hpp>
49 #include <pcl/filters/extract_indices.h>
50 #include <pcl/filters/project_inliers.h>
51 #include <pcl/kdtree/kdtree.h>
52 #include <pcl/segmentation/extract_clusters.h>
53 #include <pcl/registration/icp.h>
54 #include <pcl/io/pcd_io.h>
55 #include <dynamic_reconfigure/server.h>
56 
57 #include <velo2cam_calibration/LaserConfig.h>
58 #include "velo2cam_utils.h"
59 #include <velo2cam_calibration/ClusterCentroids.h>
60 
61 using namespace std;
62 using namespace sensor_msgs;
63 
66 int nFrames; // Used for resetting center computation
67 pcl::PointCloud<pcl::PointXYZ>::Ptr cumulative_cloud;
68 
69 // Dynamic parameters
70 double threshold_;
73 Eigen::Vector3f axis_;
78 
79 void callback(const PointCloud2::ConstPtr& laser_cloud){
80 
81  if(DEBUG) ROS_INFO("[Laser] Processing cloud...");
82 
83  pcl::PointCloud<Velodyne::Point>::Ptr velocloud (new pcl::PointCloud<Velodyne::Point>),
84  velo_filtered(new pcl::PointCloud<Velodyne::Point>),
85  pattern_cloud(new pcl::PointCloud<Velodyne::Point>);
86 
87  clouds_proc_++;
88 
89  fromROSMsg(*laser_cloud, *velocloud);
90 
91  Velodyne::addRange(*velocloud); // For latter computation of edge detection
92 
93  pcl::PointCloud<Velodyne::Point>::Ptr radius(new pcl::PointCloud<Velodyne::Point>);
94  pcl::PassThrough<Velodyne::Point> pass2;
95  pass2.setInputCloud (velocloud);
96  pass2.setFilterFieldName ("range");
97  pass2.setFilterLimits (passthrough_radius_min_, passthrough_radius_max_);
98  pass2.filter (*velo_filtered);
99 
100  sensor_msgs::PointCloud2 range_ros;
101  pcl::toROSMsg(*velo_filtered, range_ros);
102  range_ros.header = laser_cloud->header;
103  range_pub.publish(range_ros);
104 
105  // Plane segmentation
106  pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
107  pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
108 
109  pcl::SACSegmentation<Velodyne::Point> plane_segmentation;
110  plane_segmentation.setModelType (pcl::SACMODEL_PARALLEL_PLANE);
111  plane_segmentation.setDistanceThreshold (0.01);
112  plane_segmentation.setMethodType (pcl::SAC_RANSAC);
113  plane_segmentation.setAxis(Eigen::Vector3f(axis_[0], axis_[1], axis_[2]));
114  plane_segmentation.setEpsAngle (angle_threshold_);
115  plane_segmentation.setOptimizeCoefficients (true);
116  plane_segmentation.setMaxIterations(1000);
117  plane_segmentation.setInputCloud (velo_filtered);
118  plane_segmentation.segment (*inliers, *coefficients);
119 
120  if (inliers->indices.size () == 0)
121  {
122  ROS_WARN("[Laser] Could not estimate a planar model for the given dataset.");
123  return;
124  }
125 
126  // Copy coefficients to proper object for further filtering
127  Eigen::VectorXf coefficients_v(4);
128  coefficients_v(0) = coefficients->values[0];
129  coefficients_v(1) = coefficients->values[1];
130  coefficients_v(2) = coefficients->values[2];
131  coefficients_v(3) = coefficients->values[3];
132 
133  // Get edges points by range
134  vector<vector<Velodyne::Point*> > rings = Velodyne::getRings(*velocloud);
135  for (vector<vector<Velodyne::Point*> >::iterator ring = rings.begin(); ring < rings.end(); ++ring){
136  if (ring->empty()) continue;
137 
138  (*ring->begin())->intensity = 0;
139  (*(ring->end() - 1))->intensity = 0;
140  for (vector<Velodyne::Point*>::iterator pt = ring->begin() + 1; pt < ring->end() - 1; pt++){
141  Velodyne::Point *prev = *(pt - 1);
142  Velodyne::Point *succ = *(pt + 1);
143  (*pt)->intensity = max( max( prev->range-(*pt)->range, succ->range-(*pt)->range), 0.f);
144  }
145  }
146 
147  pcl::PointCloud<Velodyne::Point>::Ptr edges_cloud(new pcl::PointCloud<Velodyne::Point>);
148  float THRESHOLD = 0.5 ;
149  for (pcl::PointCloud<Velodyne::Point>::iterator pt = velocloud->points.begin(); pt < velocloud->points.end(); ++pt){
150  if(pt->intensity>THRESHOLD){
151  edges_cloud->push_back(*pt);
152  }
153  }
154 
155  if (edges_cloud->points.size () == 0)
156  {
157  ROS_WARN("[Laser] Could not detect pattern edges.");
158  return;
159  }
160 
161  // Get points belonging to plane in pattern pointcloud
162  pcl::SampleConsensusModelPlane<Velodyne::Point>::Ptr dit (new pcl::SampleConsensusModelPlane<Velodyne::Point> (edges_cloud));
163  std::vector<int> inliers2;
164  dit -> selectWithinDistance (coefficients_v, .05, inliers2); // 0.1
165  pcl::copyPointCloud<Velodyne::Point>(*edges_cloud, inliers2, *pattern_cloud);
166 
167  // Remove kps not belonging to circles by coords
168  pcl::PointCloud<pcl::PointXYZ>::Ptr circles_cloud(new pcl::PointCloud<pcl::PointXYZ>);
169  vector<vector<Velodyne::Point*> > rings2 = Velodyne::getRings(*pattern_cloud);
170  int ringsWithCircle = 0;
171  for (vector<vector<Velodyne::Point*> >::iterator ring = rings2.begin(); ring < rings2.end(); ++ring){
172  if(ring->size() < 4){
173  ring->clear();
174  }else{ // Remove first and last points in ring
175  ringsWithCircle++;
176  ring->erase(ring->begin());
177  ring->pop_back();
178 
179  for (vector<Velodyne::Point*>::iterator pt = ring->begin(); pt < ring->end(); ++pt){
180  // Velodyne specific info no longer needed for calibration
181  // so standard point is used from now on
182  pcl::PointXYZ point;
183  point.x = (*pt)->x;
184  point.y = (*pt)->y;
185  point.z = (*pt)->z;
186  circles_cloud->push_back(point);
187  }
188  }
189  }
190 
191  if(circles_cloud->points.size() > ringsWithCircle*4){
192  ROS_WARN("[Laser] Too many outliers, not computing circles.");
193  return;
194  }
195 
196  sensor_msgs::PointCloud2 velocloud_ros2;
197  pcl::toROSMsg(*circles_cloud, velocloud_ros2);
198  velocloud_ros2.header = laser_cloud->header;
199  pattern_pub.publish(velocloud_ros2);
200 
201  // Rotate cloud to face pattern plane
202  pcl::PointCloud<pcl::PointXYZ>::Ptr xy_cloud(new pcl::PointCloud<pcl::PointXYZ>);
203  Eigen::Vector3f xy_plane_normal_vector, floor_plane_normal_vector;
204  xy_plane_normal_vector[0] = 0.0;
205  xy_plane_normal_vector[1] = 0.0;
206  xy_plane_normal_vector[2] = -1.0;
207 
208  floor_plane_normal_vector[0] = coefficients->values[0];
209  floor_plane_normal_vector[1] = coefficients->values[1];
210  floor_plane_normal_vector[2] = coefficients->values[2];
211 
212  Eigen::Affine3f rotation = getRotationMatrix(floor_plane_normal_vector, xy_plane_normal_vector);
213  pcl::transformPointCloud(*circles_cloud, *xy_cloud, rotation);
214 
215  pcl::PointCloud<pcl::PointXYZ>::Ptr aux_cloud(new pcl::PointCloud<pcl::PointXYZ>);
216  pcl::PointXYZ aux_point;
217  aux_point.x = 0;
218  aux_point.y = 0;
219  aux_point.z = (-coefficients_v(3)/coefficients_v(2));
220  aux_cloud->push_back(aux_point);
221 
222  pcl::PointCloud<pcl::PointXYZ>::Ptr auxrotated_cloud(new pcl::PointCloud<pcl::PointXYZ>);
223  pcl::transformPointCloud(*aux_cloud, *auxrotated_cloud, rotation);
224 
225  sensor_msgs::PointCloud2 ros_auxpoint;
226  pcl::toROSMsg(*auxrotated_cloud, ros_auxpoint);
227  ros_auxpoint.header = laser_cloud->header;
228  auxpoint_pub.publish(ros_auxpoint);
229 
230  double zcoord_xyplane = auxrotated_cloud->at(0).z;
231 
232  pcl::PointXYZ edges_centroid;
233  pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
234  tree->setInputCloud (xy_cloud);
235 
236  std::vector<pcl::PointIndices> cluster_indices;
237  pcl::EuclideanClusterExtraction<pcl::PointXYZ> euclidean_cluster;
238  euclidean_cluster.setClusterTolerance (0.55);
239  euclidean_cluster.setMinClusterSize (12);
240  euclidean_cluster.setMaxClusterSize (RINGS_COUNT*4);
241  euclidean_cluster.setSearchMethod (tree);
242  euclidean_cluster.setInputCloud (xy_cloud);
243  euclidean_cluster.extract (cluster_indices);
244 
245  //if(DEBUG) cout << cluster_indices.size() << " clusters found from " << xy_cloud->points.size() << " points in cloud" << endl;
246 
247  for (std::vector<pcl::PointIndices>::iterator it=cluster_indices.begin(); it<cluster_indices.end(); ++it) {
248  float accx = 0., accy = 0., accz = 0.;
249  for(vector<int>::iterator it2=it->indices.begin(); it2<it->indices.end(); ++it2){
250  accx+=xy_cloud->at(*it2).x;
251  accy+=xy_cloud->at(*it2).y;
252  accz+=xy_cloud->at(*it2).z;
253  }
254  // Compute and add center to clouds
255  edges_centroid.x = accx/it->indices.size();
256  edges_centroid.y = accy/it->indices.size();
257  edges_centroid.z = accz/it->indices.size();
258  //if(DEBUG) ROS_INFO("Centroid %f %f %f", edges_centroid.x, edges_centroid.y, edges_centroid.z);
259  }
260 
261  // Extract circles
262  pcl::ModelCoefficients::Ptr coefficients3 (new pcl::ModelCoefficients);
263  pcl::PointIndices::Ptr inliers3 (new pcl::PointIndices);
264 
265  // Ransac settings for circle detecstion
266  pcl::SACSegmentation<pcl::PointXYZ> circle_segmentation;
267  circle_segmentation.setModelType (pcl::SACMODEL_CIRCLE2D);
268  circle_segmentation.setDistanceThreshold (0.04);
269  circle_segmentation.setMethodType (pcl::SAC_RANSAC);
270  circle_segmentation.setOptimizeCoefficients (true);
271  circle_segmentation.setMaxIterations(1000);
272  circle_segmentation.setRadiusLimits(circle_radius_- 0.02, circle_radius_+ 0.02);
273 
274  pcl::PointCloud<pcl::PointXYZ>::Ptr copy_cloud(new pcl::PointCloud<pcl::PointXYZ>); // Used for removing inliers
275  pcl::copyPointCloud<pcl::PointXYZ>(*xy_cloud, *copy_cloud);
276  pcl::PointCloud<pcl::PointXYZ>::Ptr circle_cloud(new pcl::PointCloud<pcl::PointXYZ>); // To store circle points
277  pcl::PointCloud<pcl::PointXYZ>::Ptr centroid_cloud(new pcl::PointCloud<pcl::PointXYZ>); // To store circle points
278  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_f(new pcl::PointCloud<pcl::PointXYZ>); // Temp pc used for swaping
279 
280  // Force pattern points to belong to computed plane
281  for (pcl::PointCloud<pcl::PointXYZ>::iterator pt = copy_cloud->points.begin(); pt < copy_cloud->points.end(); ++pt){
282  pt->z = zcoord_xyplane;
283  }
284 
285  pcl::ExtractIndices<pcl::PointXYZ> extract;
286 
287  std::vector< std::vector<float> > found_centers;
288  std::vector<pcl::PointXYZ> centroid_cloud_inliers;
289  bool valid = true;
290 
291  while ((copy_cloud->points.size()+centroid_cloud_inliers.size()) > 3 && found_centers.size()<4 && copy_cloud->points.size()){
292  circle_segmentation.setInputCloud (copy_cloud);
293  circle_segmentation.segment (*inliers3, *coefficients3);
294  if (inliers3->indices.size () == 0)
295  {
296  break;
297  }
298 
299  // Extract the inliers
300  extract.setInputCloud (copy_cloud);
301  extract.setIndices (inliers3);
302  extract.setNegative (false);
303  extract.filter (*circle_cloud);
304 
305  sensor_msgs::PointCloud2 range_ros2;
306  pcl::toROSMsg(*circle_cloud, range_ros2);
307  range_ros2.header = laser_cloud->header;
308  debug_pub.publish(range_ros2);
309 
310  // Add center point to cloud
311  pcl::PointXYZ center;
312  center.x = *coefficients3->values.begin();
313  center.y = *(coefficients3->values.begin()+1);
314  center.z = zcoord_xyplane;
315  // Make sure there is no circle at the center of the pattern or far away from it
316  double centroid_distance = sqrt(pow(fabs(edges_centroid.x-center.x),2) + pow(fabs(edges_centroid.y-center.y),2));
317  // if(DEBUG) ROS_INFO("Distance to centroid %f", centroid_distance);
318  if (centroid_distance < centroid_distance_min_){
319  valid = false;
320  for (pcl::PointCloud<pcl::PointXYZ>::iterator pt = circle_cloud->points.begin(); pt < circle_cloud->points.end(); ++pt){
321  centroid_cloud_inliers.push_back(*pt);
322  }
323  }else if(centroid_distance > centroid_distance_max_){
324  valid = false;
325  }else{
326  // if(DEBUG) ROS_INFO("Valid centroid");
327  for(std::vector<std::vector <float> >::iterator it = found_centers.begin(); it != found_centers.end(); ++it) {
328  // if(DEBUG) ROS_INFO("%f", sqrt(pow(fabs((*it)[0]-center.x),2) + pow(fabs((*it)[1]-center.y),2)));
329  if (sqrt(pow(fabs((*it)[0]-center.x),2) + pow(fabs((*it)[1]-center.y),2))<0.25){
330  valid = false;
331  break;
332  }
333  }
334 
335  // If center is valid, check if any point from wrong_circle belongs to it, and pop it if true
336  for (std::vector<pcl::PointXYZ>::iterator pt = centroid_cloud_inliers.begin(); pt < centroid_cloud_inliers.end(); ++pt){
337  pcl::PointXYZ schrodinger_pt((*pt).x, (*pt).y, (*pt).z);
338  double distance_to_cluster = sqrt(pow(schrodinger_pt.x-center.x,2) + pow(schrodinger_pt.y-center.y,2) + pow(schrodinger_pt.z-center.z,2));
339  // if(DEBUG) ROS_INFO("Distance to cluster: %lf", distance_to_cluster);
340  if(distance_to_cluster<circle_radius_+0.02){
341  centroid_cloud_inliers.erase(pt);
342  --pt; // To avoid out of range
343  }
344  }
345  // if(DEBUG) ROS_INFO("Remaining inliers %lu", centroid_cloud_inliers.size());
346  }
347 
348  if (valid){
349  // if(DEBUG) ROS_INFO("Valid circle found");
350  std::vector<float> found_center;
351  found_center.push_back(center.x);
352  found_center.push_back(center.y);
353  found_center.push_back(center.z);
354  found_centers.push_back(found_center);
355  // if(DEBUG) ROS_INFO("Remaining points in cloud %lu", copy_cloud->points.size());
356  }
357 
358  // Remove inliers from pattern cloud to find next circle
359  extract.setNegative (true);
360  extract.filter(*cloud_f);
361  copy_cloud.swap(cloud_f);
362  valid = true;
363 
364  if(DEBUG) ROS_INFO("Remaining points in cloud %lu", copy_cloud->points.size());
365  }
366 
367  if(found_centers.size() >= min_centers_found_ && found_centers.size() < 5){
368  for (std::vector<std::vector<float> >::iterator it = found_centers.begin(); it < found_centers.end(); ++it){
369  pcl::PointXYZ center;
370  center.x = (*it)[0];
371  center.y = (*it)[1];
372  center.z = (*it)[2];;
373  pcl::PointXYZ center_rotated_back = pcl::transformPoint(center, rotation.inverse());
374  center_rotated_back.x = (- coefficients->values[1] * center_rotated_back.y - coefficients->values[2] * center_rotated_back.z - coefficients->values[3])/coefficients->values[0];
375  cumulative_cloud->push_back(center_rotated_back);
376  }
377 
378  sensor_msgs::PointCloud2 ros_pointcloud;
379  pcl::toROSMsg(*cumulative_cloud, ros_pointcloud);
380  ros_pointcloud.header = laser_cloud->header;
381  cumulative_pub.publish(ros_pointcloud);
382  }else{
383  ROS_WARN("[Laser] Not enough centers: %ld", found_centers.size());
384  return;
385  }
386 
387  circle_cloud.reset();
388  copy_cloud.reset(); // Free memory
389  cloud_f.reset(); // Free memory
390 
391  nFrames++;
393 
394  pcl_msgs::ModelCoefficients m_coeff;
395  pcl_conversions::moveFromPCL(*coefficients, m_coeff);
396  m_coeff.header = laser_cloud->header;
397  coeff_pub.publish(m_coeff);
398 
399  ROS_INFO("[Laser] %d/%d frames: %ld pts in cloud", clouds_used_, clouds_proc_, cumulative_cloud->points.size());
400 
401  // Create cloud for publishing centers
402  pcl::PointCloud<pcl::PointXYZ>::Ptr centers_cloud(new pcl::PointCloud<pcl::PointXYZ>);
403 
404  // Compute circles centers
406  if (centers_cloud->points.size()>4){
408  }
409 
410  if (centers_cloud->points.size()==4){
411 
412  sensor_msgs::PointCloud2 ros2_pointcloud;
413  pcl::toROSMsg(*centers_cloud, ros2_pointcloud);
414  ros2_pointcloud.header = laser_cloud->header;
415 
416  velo2cam_calibration::ClusterCentroids to_send;
417  to_send.header = laser_cloud->header;
418  to_send.cluster_iterations = clouds_used_;
419  to_send.total_iterations = clouds_proc_;
420  to_send.cloud = ros2_pointcloud;
421 
422  centers_pub.publish(to_send);
423  //if(DEBUG) ROS_INFO("Pattern centers published");
424  }
425 }
426 
427 void param_callback(velo2cam_calibration::LaserConfig &config, uint32_t level){
428  passthrough_radius_min_ = config.passthrough_radius_min;
429  ROS_INFO("New passthrough_radius_min_ threshold: %f", passthrough_radius_min_);
430  passthrough_radius_max_ = config.passthrough_radius_max;
431  ROS_INFO("New passthrough_radius_max_ threshold: %f", passthrough_radius_max_);
432  circle_radius_ = config.circle_radius;
433  ROS_INFO("New pattern circle radius: %f", circle_radius_);
434  axis_[0] = config.x;
435  axis_[1] = config.y;
436  axis_[2] = config.z;
437  ROS_INFO("New normal axis for plane segmentation: %f, %f, %f", axis_[0], axis_[1], axis_[2]);
438  angle_threshold_ = config.angle_threshold;
439  ROS_INFO("New angle threshold: %f", angle_threshold_);
440  centroid_distance_min_ = config.centroid_distance_min;
441  ROS_INFO("New minimum distance between centroids: %f", centroid_distance_min_);
442  centroid_distance_max_ = config.centroid_distance_max;
443  ROS_INFO("New maximum distance between centroids: %f", centroid_distance_max_);
444 }
445 
446 int main(int argc, char **argv){
447  ros::init(argc, argv, "laser_pattern");
448  ros::NodeHandle nh_("~"); // LOCAL
449  ros::Subscriber sub = nh_.subscribe ("cloud1", 1, callback);
450 
451  range_pub = nh_.advertise<PointCloud2> ("range_filtered_velo", 1);
452  pattern_pub = nh_.advertise<PointCloud2> ("pattern_circles", 1);
453  auxpoint_pub = nh_.advertise<PointCloud2> ("rotated_pattern", 1);
454  cumulative_pub = nh_.advertise<PointCloud2> ("cumulative_cloud", 1);
455  centers_pub = nh_.advertise<velo2cam_calibration::ClusterCentroids> ("centers_cloud", 1);
456 
457  debug_pub = nh_.advertise<PointCloud2> ("debug", 1);
458 
459  coeff_pub = nh_.advertise<pcl_msgs::ModelCoefficients> ("plane_model", 1);
460 
461  nh_.param("cluster_size", cluster_size_, 0.02);
462  nh_.param("min_centers_found", min_centers_found_, 4);
463 
464  nFrames = 0;
465  cumulative_cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
466 
467  dynamic_reconfigure::Server<velo2cam_calibration::LaserConfig> server;
468  dynamic_reconfigure::Server<velo2cam_calibration::LaserConfig>::CallbackType f;
469  f = boost::bind(param_callback, _1, _2);
470  server.setCallback(f);
471 
472  ros::spin();
473  return 0;
474 }
void param_callback(velo2cam_calibration::LaserConfig &config, uint32_t level)
ros::Publisher cumulative_pub
ros::Publisher pattern_pub
double threshold_
void publish(const boost::shared_ptr< M > &message) const
vector< vector< Point * > > getRings(pcl::PointCloud< Velodyne::Point > &pc)
f
int main(int argc, char **argv)
float intensity
laser intensity reading
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
pcl::PointCloud< Velodyne::Point >::Ptr edges_cloud
Definition: levinson.cpp:73
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
double centroid_distance_max_
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
double centroid_distance_min_
double circle_radius_
#define ROS_WARN(...)
pcl::PointCloud< pcl::PointXYZ >::Ptr cumulative_cloud
ros::Publisher debug_pub
ros::Publisher centers_pub
ROSCPP_DECL void spin(Spinner &spinner)
double passthrough_radius_min_
pcl::PointCloud< pcl::PointXYZ >::Ptr laser_cloud
#define DEBUG
int nFrames
#define ROS_INFO(...)
ros::Publisher coeff_pub
bool param(const std::string &param_name, T &param_val, const T &default_val) const
double angle_threshold_
void callback(const PointCloud2::ConstPtr &laser_cloud)
ros::Publisher aux_pub
int clouds_used_
void addRange(pcl::PointCloud< Velodyne::Point > &pc)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
int min_centers_found_
Eigen::Affine3f getRotationMatrix(Eigen::Vector3f source, Eigen::Vector3f target)
void getCenterClusters(pcl::PointCloud< pcl::PointXYZ >::Ptr cloud_in, pcl::PointCloud< pcl::PointXYZ >::Ptr centers_cloud, double cluster_tolerance=0.10, int min_cluster_size=15, int max_cluster_size=200, bool verbosity=true)
int clouds_proc_
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
Eigen::Vector3f axis_
ros::Publisher range_pub
double cluster_size_
void toROSMsg(const sensor_msgs::PointCloud2 &cloud, sensor_msgs::Image &image)
void moveFromPCL(pcl::PCLImage &pcl_image, sensor_msgs::Image &image)
ros::Publisher auxpoint_pub
double max(double a, double b)
double passthrough_radius_max_
static const int RINGS_COUNT


velo2cam_calibration
Author(s): Jorge Beltran , Carlos Guindel
autogenerated on Thu Feb 28 2019 03:24:25