00001 #include "ros/ros.h"
00002
00003 #include "sensor_msgs/point_cloud_conversion.h"
00004
00005 #include <boost/make_shared.hpp>
00006 #include "pcl/io/pcd_io.h"
00007 #include <pcl/features/fpfh_omp.h>
00008 #include <pcl/kdtree/kdtree_flann.h>
00009 #include <pcl/features/normal_3d_omp.h>
00010 #include "pcl/filters/voxel_grid.h"
00011
00012
00013 #include "feature_extractor_fpfh/FPFHCalc.h"
00014 #include "feature_extractor_fpfh/FPFHHist.h"
00015 #include "feature_extractor_fpfh/fpfh_node.h"
00016
00017 #include "message_filters/subscriber.h"
00018 #include "message_filters/time_synchronizer.h"
00019
00020 using namespace pcl;
00021 using namespace std;
00022 using namespace message_filters;
00023 typedef KdTree<PointXYZ>::Ptr KdTreePtr;
00024
00025 using namespace message_filters;
00026
00027
00028 FPFHNode::FPFHNode(ros::NodeHandle &n): n_(n)
00029 {
00030 hist_publisher = n_.advertise<feature_extractor_fpfh::FPFHHist>("fpfh_hist", 10);
00031 fpfh_service = n_.advertiseService("fpfh", &FPFHNode::fpfh_srv_cb, this);
00032 subsample_service = n_.advertiseService("subsample", &FPFHNode::subsample_srv_cb, this);
00033 }
00034
00035
00036 bool FPFHNode::fpfh_srv_cb(feature_extractor_fpfh::FPFHCalc::Request &req,
00037 feature_extractor_fpfh::FPFHCalc::Response &res)
00038 {
00039
00040
00041
00042 sensor_msgs::PointCloud2 *cloud2 = new sensor_msgs::PointCloud2();
00043 sensor_msgs::convertPointCloudToPointCloud2(req.input, *cloud2);
00044 ROS_INFO("cloud has %d points", cloud2->width * cloud2->height);
00045
00046 const sensor_msgs::PointCloud2::ConstPtr input_cloud((const sensor_msgs::PointCloud2 *) cloud2);
00047 ROS_INFO("done1\n");
00048 process_point_cloud(input_cloud, res.hist);
00049 ROS_INFO("done2\n");
00050
00051 return true;
00052 }
00053
00054
00055 bool FPFHNode::subsample_srv_cb(feature_extractor_fpfh::SubsampleCalc::Request &req,
00056 feature_extractor_fpfh::SubsampleCalc::Response &res)
00057 {
00058
00059 float resolution = .005;
00060
00061 sensor_msgs::PointCloud2 *cloud2 = new sensor_msgs::PointCloud2();
00062 sensor_msgs::convertPointCloudToPointCloud2(req.input, *cloud2);
00063 ROS_INFO("before cloud has %d points", cloud2->width * cloud2->height);
00064 const sensor_msgs::PointCloud2::ConstPtr input_cloud((const sensor_msgs::PointCloud2 *) cloud2);
00065
00066 sensor_msgs::PointCloud2 pc2_filtered;
00067 pcl::VoxelGrid<sensor_msgs::PointCloud2> sor;
00068 sor.setInputCloud(input_cloud);
00069 sor.setLeafSize (resolution, resolution, resolution);
00070 sor.filter(pc2_filtered);
00071 sensor_msgs::convertPointCloud2ToPointCloud(pc2_filtered, res.output);
00072 ROS_INFO("after cloud has %d points", pc2_filtered.width * pc2_filtered.height);
00073
00074 return true;
00075 }
00076
00077
00078 void FPFHNode::process_point_cloud(const sensor_msgs::PointCloud2::ConstPtr& input_cloud,
00079 feature_extractor_fpfh::FPFHHist &hist)
00080 {
00081 ROS_INFO("done3\n");
00082 float fpfh_leaf_size = .01;
00083 ROS_INFO("cloud has %d points", input_cloud->width * input_cloud->height);
00084
00085 sensor_msgs::PointCloud2::Ptr cloud_filtered(new sensor_msgs::PointCloud2());
00086 pcl::VoxelGrid<sensor_msgs::PointCloud2> sor;
00087 sor.setInputCloud(input_cloud);
00088 sor.setLeafSize (fpfh_leaf_size, fpfh_leaf_size, fpfh_leaf_size);
00089 sor.filter(*cloud_filtered);
00090
00091
00092 float leaf_size = .005;
00093 sensor_msgs::PointCloud2::Ptr cloud_filtered2(new sensor_msgs::PointCloud2());
00094 pcl::VoxelGrid<sensor_msgs::PointCloud2> sor2;
00095 sor2.setInputCloud(input_cloud);
00096 sor2.setLeafSize (leaf_size, leaf_size, leaf_size);
00097 sor2.filter(*cloud_filtered2);
00098 PointCloud<PointXYZ> pcl_input_cloud_small;
00099 fromROSMsg(*cloud_filtered2, pcl_input_cloud_small);
00100
00101 ROS_INFO("after coarse filtering: %d points", cloud_filtered->width * cloud_filtered->height);
00102 ROS_INFO("after fine filtering: %d points", cloud_filtered2->width * cloud_filtered2->height);
00103
00104 if ((cloud_filtered->width * cloud_filtered->height) == 0)
00105 {
00106 return;
00107 }
00108 PointCloud<PointXYZ> cloud, pcl_input_cloud;
00109 fromROSMsg(*cloud_filtered, cloud);
00110 fromROSMsg(*input_cloud, pcl_input_cloud);
00111 std::vector<int> indices;
00112 indices.resize (cloud.points.size());
00113 for (size_t i = 0; i < indices.size (); ++i) { indices[i] = i; }
00114 ROS_INFO("here1");
00115
00116 KdTreePtr tree;
00117 tree.reset(new KdTreeFLANN<PointXYZ> (false));
00118 tree->setInputCloud(cloud.makeShared());
00119
00120 ROS_INFO("here2");
00121 PointCloud<Normal>::Ptr normals(new PointCloud<Normal>());
00122 boost::shared_ptr< vector<int> > indicesptr(new vector<int> (indices));
00123 NormalEstimation<PointXYZ, Normal> normal_estimator;
00124 ROS_INFO("here4");
00125
00126 normal_estimator.setIndices(indicesptr);
00127 normal_estimator.setSearchMethod(tree);
00128 normal_estimator.setKSearch(10);
00129
00130
00131 ROS_DEBUG("fpfh_Calculating normals...\n");
00132 normal_estimator.setInputCloud(cloud.makeShared());
00133 normal_estimator.compute(*normals);
00134
00135
00136 FPFHEstimationOMP<PointXYZ, Normal, FPFHSignature33> fpfh(4);
00137
00138 PointCloud<FPFHSignature33>::Ptr fphists (new PointCloud<FPFHSignature33>());
00139 ROS_INFO("here5");
00140
00141
00142 int d1, d2, d3;
00143 d1 = d2 = d3 = 11;
00144 fpfh.setNrSubdivisions(d1, d2, d3);
00145 fpfh.setSearchMethod(tree);
00146 fpfh.setIndices(indicesptr);
00147 fpfh.setKSearch(40);
00148
00149 ROS_DEBUG("Calculating fpfh...\n");
00150 fpfh.setInputNormals(normals);
00151 fpfh.setInputCloud(cloud.makeShared());
00152 fpfh.compute(*fphists);
00153
00154 ROS_INFO("here6");
00155 hist.header = input_cloud->header;
00156 hist.dim[0] = d1;
00157 hist.dim[1] = d2;
00158 hist.dim[2] = d3;
00159 unsigned int total_size = d1+d2+d3;
00160 hist.histograms.resize(total_size * cloud.points.size());
00161 hist.hpoints3d.resize(3*cloud.points.size());
00162 ROS_DEBUG("copying into message...\n");
00163 for (unsigned int i = 0; i < cloud.points.size(); i++)
00164 {
00165 for (unsigned int j = 0; j < total_size; j++)
00166 {
00167 hist.histograms[i*total_size + j] = fphists->points[i].histogram[j];
00168 }
00169
00170 hist.hpoints3d[3*i] = cloud.points[i].x;
00171 hist.hpoints3d[3*i+1] = cloud.points[i].y;
00172 hist.hpoints3d[3*i+2] = cloud.points[i].z;
00173 }
00174 hist.hist_npoints = cloud.points.size();
00175
00176 ROS_INFO("here7");
00177 hist.origpoints.resize(3*pcl_input_cloud_small.points.size());
00178 for (unsigned int i = 0; i < pcl_input_cloud_small.points.size(); i++)
00179 {
00180 hist.origpoints[3*i] = pcl_input_cloud_small.points[i].x;
00181 hist.origpoints[3*i+1] = pcl_input_cloud_small.points[i].y;
00182 hist.origpoints[3*i+2] = pcl_input_cloud_small.points[i].z;
00183 }
00184 hist.original_npoints = pcl_input_cloud_small.size();
00185 ROS_INFO("here8");
00186 }
00187
00188
00189 void FPFHNode::message_cb(const sensor_msgs::Image::ConstPtr& image,
00190 const sensor_msgs::PointCloud2::ConstPtr& input_cloud)
00191 {
00192
00193 feature_extractor_fpfh::FPFHHist hist;
00194 process_point_cloud(input_cloud, hist);
00195
00196 hist.image.header = image->header;
00197 hist.image.height = image->height;
00198 hist.image.width = image->width;
00199 hist.image.encoding = image->encoding;
00200 hist.image.is_bigendian = image->is_bigendian;
00201 hist.image.step = image->step;
00202 hist.image.data.resize(image->data.size());
00203 for (unsigned int i = 0; i < image->data.size(); i++)
00204 {
00205 hist.image.data[i] = image->data[i];
00206 }
00207
00208 hist_publisher.publish(boost::make_shared<const feature_extractor_fpfh::FPFHHist>(hist));
00209 ROS_INFO("publish histogram done.\n");
00210 }
00211
00212 int main(int argc, char** argv)
00213 {
00214 ros::init(argc, argv, "fpfh_calc");
00215 ros::NodeHandle nh;
00216 FPFHNode mc(nh);
00217
00218 message_filters::Subscriber<sensor_msgs::Image> image_sub(nh, "image", 1);
00219 message_filters::Subscriber<sensor_msgs::PointCloud2> pc_sub(nh, "points2", 1);
00220 TimeSynchronizer<sensor_msgs::Image, sensor_msgs::PointCloud2> sync(image_sub, pc_sub, 10);
00221 sync.registerCallback(boost::bind(&FPFHNode::message_cb, &mc, _1, _2));
00222
00223 ROS_INFO("started!");
00224 ros::spin();
00225 return 0;
00226 }
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00306
00307
00308
00309
00310
00311
00313
00314
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362