25 #define PCL_NO_PRECOMPILE 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> 57 #include <velo2cam_calibration/LaserConfig.h> 59 #include <velo2cam_calibration/ClusterCentroids.h> 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>);
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");
98 pass2.filter (*velo_filtered);
100 sensor_msgs::PointCloud2 range_ros;
102 range_ros.header = laser_cloud->header;
106 pcl::ModelCoefficients::Ptr coefficients (
new pcl::ModelCoefficients);
107 pcl::PointIndices::Ptr inliers (
new pcl::PointIndices);
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]));
115 plane_segmentation.setOptimizeCoefficients (
true);
116 plane_segmentation.setMaxIterations(1000);
117 plane_segmentation.setInputCloud (velo_filtered);
118 plane_segmentation.segment (*inliers, *coefficients);
120 if (inliers->indices.size () == 0)
122 ROS_WARN(
"[Laser] Could not estimate a planar model for the given dataset.");
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];
135 for (vector<vector<Velodyne::Point*> >::iterator ring = rings.begin(); ring < rings.end(); ++ring){
136 if (ring->empty())
continue;
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++){
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);
155 if (edges_cloud->points.size () == 0)
157 ROS_WARN(
"[Laser] Could not detect pattern edges.");
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);
165 pcl::copyPointCloud<Velodyne::Point>(*
edges_cloud, inliers2, *pattern_cloud);
168 pcl::PointCloud<pcl::PointXYZ>::Ptr circles_cloud(
new pcl::PointCloud<pcl::PointXYZ>);
170 int ringsWithCircle = 0;
171 for (vector<vector<Velodyne::Point*> >::iterator ring = rings2.begin(); ring < rings2.end(); ++ring){
172 if(ring->size() < 4){
176 ring->erase(ring->begin());
179 for (vector<Velodyne::Point*>::iterator pt = ring->begin(); pt < ring->end(); ++pt){
186 circles_cloud->push_back(point);
191 if(circles_cloud->points.size() > ringsWithCircle*4){
192 ROS_WARN(
"[Laser] Too many outliers, not computing circles.");
196 sensor_msgs::PointCloud2 velocloud_ros2;
198 velocloud_ros2.header = laser_cloud->header;
199 pattern_pub.
publish(velocloud_ros2);
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;
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];
212 Eigen::Affine3f rotation =
getRotationMatrix(floor_plane_normal_vector, xy_plane_normal_vector);
213 pcl::transformPointCloud(*circles_cloud, *xy_cloud, rotation);
215 pcl::PointCloud<pcl::PointXYZ>::Ptr aux_cloud(
new pcl::PointCloud<pcl::PointXYZ>);
216 pcl::PointXYZ aux_point;
219 aux_point.z = (-coefficients_v(3)/coefficients_v(2));
220 aux_cloud->push_back(aux_point);
222 pcl::PointCloud<pcl::PointXYZ>::Ptr auxrotated_cloud(
new pcl::PointCloud<pcl::PointXYZ>);
223 pcl::transformPointCloud(*aux_cloud, *auxrotated_cloud, rotation);
225 sensor_msgs::PointCloud2 ros_auxpoint;
227 ros_auxpoint.header = laser_cloud->header;
228 auxpoint_pub.
publish(ros_auxpoint);
230 double zcoord_xyplane = auxrotated_cloud->at(0).z;
232 pcl::PointXYZ edges_centroid;
233 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (
new pcl::search::KdTree<pcl::PointXYZ>);
234 tree->setInputCloud (xy_cloud);
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);
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;
255 edges_centroid.x = accx/it->indices.size();
256 edges_centroid.y = accy/it->indices.size();
257 edges_centroid.z = accz/it->indices.size();
262 pcl::ModelCoefficients::Ptr coefficients3 (
new pcl::ModelCoefficients);
263 pcl::PointIndices::Ptr inliers3 (
new pcl::PointIndices);
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);
274 pcl::PointCloud<pcl::PointXYZ>::Ptr copy_cloud(
new pcl::PointCloud<pcl::PointXYZ>);
275 pcl::copyPointCloud<pcl::PointXYZ>(*xy_cloud, *copy_cloud);
276 pcl::PointCloud<pcl::PointXYZ>::Ptr circle_cloud(
new pcl::PointCloud<pcl::PointXYZ>);
277 pcl::PointCloud<pcl::PointXYZ>::Ptr centroid_cloud(
new pcl::PointCloud<pcl::PointXYZ>);
278 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_f(
new pcl::PointCloud<pcl::PointXYZ>);
281 for (pcl::PointCloud<pcl::PointXYZ>::iterator pt = copy_cloud->points.begin(); pt < copy_cloud->points.end(); ++pt){
282 pt->z = zcoord_xyplane;
285 pcl::ExtractIndices<pcl::PointXYZ> extract;
287 std::vector< std::vector<float> > found_centers;
288 std::vector<pcl::PointXYZ> centroid_cloud_inliers;
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)
300 extract.setInputCloud (copy_cloud);
301 extract.setIndices (inliers3);
302 extract.setNegative (
false);
303 extract.filter (*circle_cloud);
305 sensor_msgs::PointCloud2 range_ros2;
307 range_ros2.header = laser_cloud->header;
311 pcl::PointXYZ center;
312 center.x = *coefficients3->values.begin();
313 center.y = *(coefficients3->values.begin()+1);
314 center.z = zcoord_xyplane;
316 double centroid_distance =
sqrt(
pow(fabs(edges_centroid.x-center.x),2) +
pow(fabs(edges_centroid.y-center.y),2));
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);
327 for(std::vector<std::vector <float> >::iterator it = found_centers.begin(); it != found_centers.end(); ++it) {
329 if (
sqrt(
pow(fabs((*it)[0]-center.x),2) +
pow(fabs((*it)[1]-center.y),2))<0.25){
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));
341 centroid_cloud_inliers.erase(pt);
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);
359 extract.setNegative (
true);
360 extract.filter(*cloud_f);
361 copy_cloud.swap(cloud_f);
364 if(
DEBUG)
ROS_INFO(
"Remaining points in cloud %lu", copy_cloud->points.size());
368 for (std::vector<std::vector<float> >::iterator it = found_centers.begin(); it < found_centers.end(); ++it){
369 pcl::PointXYZ center;
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];
378 sensor_msgs::PointCloud2 ros_pointcloud;
380 ros_pointcloud.header = laser_cloud->header;
381 cumulative_pub.
publish(ros_pointcloud);
383 ROS_WARN(
"[Laser] Not enough centers: %ld", found_centers.size());
387 circle_cloud.reset();
394 pcl_msgs::ModelCoefficients m_coeff;
396 m_coeff.header = laser_cloud->header;
402 pcl::PointCloud<pcl::PointXYZ>::Ptr centers_cloud(
new pcl::PointCloud<pcl::PointXYZ>);
406 if (centers_cloud->points.size()>4){
410 if (centers_cloud->points.size()==4){
412 sensor_msgs::PointCloud2 ros2_pointcloud;
414 ros2_pointcloud.header = laser_cloud->header;
416 velo2cam_calibration::ClusterCentroids to_send;
417 to_send.header = laser_cloud->header;
420 to_send.cloud = ros2_pointcloud;
446 int main(
int argc,
char **argv){
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);
457 debug_pub = nh_.
advertise<PointCloud2> (
"debug", 1);
459 coeff_pub = nh_.
advertise<pcl_msgs::ModelCoefficients> (
"plane_model", 1);
465 cumulative_cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(
new pcl::PointCloud<pcl::PointXYZ>);
467 dynamic_reconfigure::Server<velo2cam_calibration::LaserConfig> server;
468 dynamic_reconfigure::Server<velo2cam_calibration::LaserConfig>::CallbackType
f;
470 server.setCallback(f);
void param_callback(velo2cam_calibration::LaserConfig &config, uint32_t level)
ros::Publisher cumulative_pub
ros::Publisher pattern_pub
void publish(const boost::shared_ptr< M > &message) const
vector< vector< Point * > > getRings(pcl::PointCloud< Velodyne::Point > &pc)
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
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_
pcl::PointCloud< pcl::PointXYZ >::Ptr cumulative_cloud
ros::Publisher centers_pub
ROSCPP_DECL void spin(Spinner &spinner)
double passthrough_radius_min_
pcl::PointCloud< pcl::PointXYZ >::Ptr laser_cloud
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
void callback(const PointCloud2::ConstPtr &laser_cloud)
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)
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)
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
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