00001
00057 #include <pcl/console/parse.h>
00058 #include <pcl/point_types.h>
00059 #include <pcl/point_cloud.h>
00060 #include <pcl/point_representation.h>
00061
00062 #include <pcl/io/pcd_io.h>
00063 #include <pcl/ros/conversions.h>
00064 #ifdef GICP_ENABLE
00065 #include <pcl/keypoints/uniform_sampling.h>
00066 #include <pcl/features/normal_3d.h>
00067 #include <pcl/features/fpfh.h>
00068 #include <pcl/registration/correspondence_estimation.h>
00069 #include <pcl/registration/correspondence_rejection_distance.h>
00070 #include <pcl/registration/transformation_estimation_svd.h>
00071
00072 using namespace std;
00073 using namespace sensor_msgs;
00074 using namespace pcl;
00075 using namespace pcl::io;
00076 using namespace pcl::console;
00077 using namespace pcl::registration;
00078 PointCloud<PointXYZ>::Ptr src, tgt;
00079
00081 void
00082 estimateKeypoints (const PointCloud<PointXYZ>::Ptr &src,
00083 const PointCloud<PointXYZ>::Ptr &tgt,
00084 PointCloud<PointXYZ> &keypoints_src,
00085 PointCloud<PointXYZ> &keypoints_tgt)
00086 {
00087 PointCloud<int> keypoints_src_idx, keypoints_tgt_idx;
00088
00089 UniformSampling<PointXYZ> uniform;
00090 uniform.setRadiusSearch (1);
00091
00092 uniform.setInputCloud (src);
00093 uniform.compute (keypoints_src_idx);
00094 copyPointCloud<PointXYZ, PointXYZ> (*src, keypoints_src_idx.points, keypoints_src);
00095
00096 uniform.setInputCloud (tgt);
00097 uniform.compute (keypoints_tgt_idx);
00098 copyPointCloud<PointXYZ, PointXYZ> (*tgt, keypoints_tgt_idx.points, keypoints_tgt);
00099
00100
00101
00102 savePCDFileBinary ("keypoints_src.pcd", keypoints_src);
00103 savePCDFileBinary ("keypoints_tgt.pcd", keypoints_tgt);
00104 }
00105
00107 void
00108 estimateNormals (const PointCloud<PointXYZ>::Ptr &src,
00109 const PointCloud<PointXYZ>::Ptr &tgt,
00110 PointCloud<Normal> &normals_src,
00111 PointCloud<Normal> &normals_tgt)
00112 {
00113 NormalEstimation<PointXYZ, Normal> normal_est;
00114 normal_est.setInputCloud (src);
00115 normal_est.setRadiusSearch (0.5);
00116 normal_est.compute (normals_src);
00117
00118 normal_est.setInputCloud (tgt);
00119 normal_est.compute (normals_tgt);
00120
00121
00122
00123 PointCloud<PointNormal> s, t;
00124 copyPointCloud<PointXYZ, PointNormal> (*src, s);
00125 copyPointCloud<Normal, PointNormal> (normals_src, s);
00126 copyPointCloud<PointXYZ, PointNormal> (*tgt, t);
00127 copyPointCloud<Normal, PointNormal> (normals_tgt, t);
00128 savePCDFileBinary ("normals_src.pcd", s);
00129 savePCDFileBinary ("normals_tgt.pcd", t);
00130 }
00131
00133 void
00134 estimateFPFH (const PointCloud<PointXYZ>::Ptr &src,
00135 const PointCloud<PointXYZ>::Ptr &tgt,
00136 const PointCloud<Normal>::Ptr &normals_src,
00137 const PointCloud<Normal>::Ptr &normals_tgt,
00138 const PointCloud<PointXYZ>::Ptr &keypoints_src,
00139 const PointCloud<PointXYZ>::Ptr &keypoints_tgt,
00140 PointCloud<FPFHSignature33> &fpfhs_src,
00141 PointCloud<FPFHSignature33> &fpfhs_tgt)
00142 {
00143 FPFHEstimation<PointXYZ, Normal, FPFHSignature33> fpfh_est;
00144 fpfh_est.setInputCloud (keypoints_src);
00145 fpfh_est.setInputNormals (normals_src);
00146 fpfh_est.setRadiusSearch (1);
00147 fpfh_est.setSearchSurface (src);
00148 fpfh_est.compute (fpfhs_src);
00149
00150 fpfh_est.setInputCloud (keypoints_tgt);
00151 fpfh_est.setInputNormals (normals_tgt);
00152 fpfh_est.setSearchSurface (tgt);
00153 fpfh_est.compute (fpfhs_tgt);
00154
00155
00156
00157 PointCloud2 s, t, out;
00158
00159 savePCDFile ("fpfhs_src.pcd", out);
00160
00161 savePCDFile ("fpfhs_tgt.pcd", out);
00162 }
00163
00165 void
00166 findCorrespondences (const PointCloud<FPFHSignature33>::Ptr &fpfhs_src,
00167 const PointCloud<FPFHSignature33>::Ptr &fpfhs_tgt,
00168 Correspondences &all_correspondences)
00169 {
00170 CorrespondenceEstimation<FPFHSignature33, FPFHSignature33> est;
00171 est.setInputCloud (fpfhs_src);
00172 est.setInputTarget (fpfhs_tgt);
00173 est.determineReciprocalCorrespondences (all_correspondences);
00174 }
00175
00177 void
00178 rejectBadCorrespondences (const CorrespondencesPtr &all_correspondences,
00179 const PointCloud<PointXYZ>::Ptr &keypoints_src,
00180 const PointCloud<PointXYZ>::Ptr &keypoints_tgt,
00181 Correspondences &remaining_correspondences)
00182 {
00183 CorrespondenceRejectorDistance rej;
00184 rej.setInputCloud<PointXYZ> (keypoints_src);
00185 rej.setInputTarget<PointXYZ> (keypoints_tgt);
00186 rej.setMaximumDistance (1);
00187 rej.setInputCorrespondences (all_correspondences);
00188 rej.getCorrespondences (remaining_correspondences);
00189 }
00190
00191
00193 void
00194 computeTransformation (const PointCloud<PointXYZ>::Ptr &src,
00195 const PointCloud<PointXYZ>::Ptr &tgt,
00196 Eigen::Matrix4f &transform)
00197 {
00198
00199 PointCloud<PointXYZ>::Ptr keypoints_src (new PointCloud<PointXYZ>),
00200 keypoints_tgt (new PointCloud<PointXYZ>);
00201
00202 estimateKeypoints (src, tgt, *keypoints_src, *keypoints_tgt);
00203 print_info ("Found %zu and %zu keypoints for the source and target datasets.\n", keypoints_src->points.size (), keypoints_tgt->points.size ());
00204
00205
00206 PointCloud<Normal>::Ptr normals_src (new PointCloud<Normal>),
00207 normals_tgt (new PointCloud<Normal>);
00208 estimateNormals (src, tgt, *normals_src, *normals_tgt);
00209 print_info ("Estimated %zu and %zu normals for the source and target datasets.\n", normals_src->points.size (), normals_tgt->points.size ());
00210
00211
00212 PointCloud<FPFHSignature33>::Ptr fpfhs_src (new PointCloud<FPFHSignature33>),
00213 fpfhs_tgt (new PointCloud<FPFHSignature33>);
00214 estimateFPFH (src, tgt, normals_src, normals_tgt, keypoints_src, keypoints_tgt, *fpfhs_src, *fpfhs_tgt);
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224 CorrespondencesPtr all_correspondences (new Correspondences),
00225 good_correspondences (new Correspondences);
00226 findCorrespondences (fpfhs_src, fpfhs_tgt, *all_correspondences);
00227
00228
00229 rejectBadCorrespondences (all_correspondences, keypoints_src, keypoints_tgt, *good_correspondences);
00230
00231 for (int i = 0; i < good_correspondences->size (); ++i)
00232 std::cerr << good_correspondences->at (i) << std::endl;
00233
00234 TransformationEstimationSVD<PointXYZ, PointXYZ> trans_est;
00235 trans_est.estimateRigidTransformation (*keypoints_src, *keypoints_tgt, *good_correspondences, transform);
00236 }
00237
00238
00239 int
00240 main (int argc, char** argv)
00241 {
00242
00243 std::vector<int> p_file_indices;
00244 p_file_indices = parse_file_extension_argument (argc, argv, ".pcd");
00245 if (p_file_indices.size () != 2)
00246 {
00247 print_error ("Need one input source PCD file and one input target PCD file to continue.\n");
00248 print_error ("Example: %s source.pcd target.pcd\n", argv[0]);
00249 return (-1);
00250 }
00251
00252
00253 print_info ("Loading %s as source and %s as target...\n", argv[p_file_indices[0]], argv[p_file_indices[1]]);
00254 src.reset (new PointCloud<PointXYZ>);
00255 tgt.reset (new PointCloud<PointXYZ>);
00256 if (loadPCDFile (argv[p_file_indices[0]], *src) == -1 || loadPCDFile (argv[p_file_indices[1]], *tgt) == -1)
00257 {
00258 print_error ("Error reading the input files!\n");
00259 return (-1);
00260 }
00261
00262
00263 Eigen::Matrix4f transform;
00264 computeTransformation (src, tgt, transform);
00265
00266 std::cerr << transform << std::endl;
00267
00268 PointCloud<PointXYZ> output;
00269 transformPointCloud (*src, output, transform);
00270 savePCDFileBinary ("source_transformed.pcd", output);
00271 }
00272
00273 #else
00274 int main() {return 0;}
00275 #endif