00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include <gtest/gtest.h>
00041
00042 #include <limits>
00043
00044 #include <pcl/point_types.h>
00045 #include <pcl/io/pcd_io.h>
00046 #include <pcl/registration/eigen.h>
00047 #include <pcl/registration/correspondence_estimation.h>
00048 #include <pcl/registration/correspondence_rejection_distance.h>
00049 #include <pcl/registration/correspondence_rejection_median_distance.h>
00050 #include <pcl/registration/correspondence_rejection_surface_normal.h>
00051 #include <pcl/registration/correspondence_rejection.h>
00052 #include <pcl/registration/correspondence_rejection_one_to_one.h>
00053 #include <pcl/registration/correspondence_rejection_sample_consensus.h>
00054 #include <pcl/registration/correspondence_rejection_trimmed.h>
00055 #include <pcl/registration/correspondence_rejection_var_trimmed.h>
00056 #include <pcl/registration/transformation_estimation_lm.h>
00057 #include <pcl/registration/transformation_estimation_svd.h>
00058 #include <pcl/registration/transformation_estimation_point_to_plane_lls.h>
00059 #include <pcl/registration/transformation_estimation_point_to_plane.h>
00060 #include <pcl/features/normal_3d.h>
00061
00062 #include "test_registration_api_data.h"
00063
00064 typedef pcl::PointXYZ PointXYZ;
00065 typedef pcl::PointCloud <PointXYZ> CloudXYZ;
00066 typedef CloudXYZ::Ptr CloudXYZPtr;
00067 typedef CloudXYZ::ConstPtr CloudXYZConstPtr;
00068
00069 typedef pcl::PointNormal PointNormal;
00070 typedef pcl::PointCloud <PointNormal> CloudNormal;
00071 typedef CloudNormal::Ptr CloudNormalPtr;
00072 typedef CloudNormal::ConstPtr CloudNormalConstPtr;
00073
00074 CloudXYZ cloud_source, cloud_target, cloud_reg;
00075
00077 TEST (PCL, CorrespondenceEstimation)
00078 {
00079 CloudXYZConstPtr source (new CloudXYZ (cloud_source));
00080 CloudXYZConstPtr target (new CloudXYZ (cloud_target));
00081
00082 boost::shared_ptr<pcl::Correspondences> correspondences (new pcl::Correspondences);
00083 pcl::registration::CorrespondenceEstimation<PointXYZ, PointXYZ> corr_est;
00084 corr_est.setInputSource (source);
00085 corr_est.setInputTarget (target);
00086 corr_est.determineCorrespondences (*correspondences);
00087
00088
00089 EXPECT_EQ (int (correspondences->size ()), nr_original_correspondences);
00090 if (int (correspondences->size ()) == nr_original_correspondences)
00091 {
00092 for (int i = 0; i < nr_original_correspondences; ++i)
00093 {
00094 EXPECT_EQ ((*correspondences)[i].index_query, i);
00095 EXPECT_EQ ((*correspondences)[i].index_match, correspondences_original[i][1]);
00096 }
00097 }
00098 }
00099
00101 TEST (PCL, CorrespondenceEstimationReciprocal)
00102 {
00103 CloudXYZConstPtr source (new CloudXYZ (cloud_source));
00104 CloudXYZConstPtr target (new CloudXYZ (cloud_target));
00105
00106 boost::shared_ptr<pcl::Correspondences> correspondences (new pcl::Correspondences);
00107 pcl::registration::CorrespondenceEstimation<PointXYZ, PointXYZ> corr_est;
00108 corr_est.setInputSource (source);
00109 corr_est.setInputTarget (target);
00110 corr_est.determineReciprocalCorrespondences (*correspondences);
00111
00112
00113 EXPECT_EQ (int (correspondences->size ()), nr_reciprocal_correspondences);
00114 if (int (correspondences->size ()) == nr_reciprocal_correspondences)
00115 {
00116 for (int i = 0; i < nr_reciprocal_correspondences; ++i)
00117 {
00118 EXPECT_EQ ((*correspondences)[i].index_query, correspondences_reciprocal[i][0]);
00119 EXPECT_EQ ((*correspondences)[i].index_match, correspondences_reciprocal[i][1]);
00120 }
00121 }
00122 }
00123
00125 TEST (PCL, CorrespondenceRejectorDistance)
00126 {
00127 CloudXYZConstPtr source (new CloudXYZ (cloud_source));
00128 CloudXYZConstPtr target (new CloudXYZ (cloud_target));
00129
00130
00131 boost::shared_ptr<pcl::Correspondences> correspondences (new pcl::Correspondences);
00132 pcl::registration::CorrespondenceEstimation<PointXYZ, PointXYZ> corr_est;
00133 #pragma GCC diagnostic push
00134 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
00135 corr_est.setInputCloud (source);
00136 source = corr_est.getInputCloud ();
00137 #pragma GCC diagnostic pop
00138 corr_est.setInputSource (source);
00139 corr_est.setInputTarget (target);
00140 corr_est.determineCorrespondences (*correspondences);
00141
00142 boost::shared_ptr<pcl::Correspondences> correspondences_result_rej_dist (new pcl::Correspondences);
00143 pcl::registration::CorrespondenceRejectorDistance corr_rej_dist;
00144 corr_rej_dist.setInputCorrespondences (correspondences);
00145 corr_rej_dist.setMaximumDistance (rej_dist_max_dist);
00146 corr_rej_dist.getCorrespondences (*correspondences_result_rej_dist);
00147
00148
00149 EXPECT_EQ (int (correspondences_result_rej_dist->size ()), nr_correspondences_result_rej_dist);
00150 if (int (correspondences_result_rej_dist->size ()) == nr_correspondences_result_rej_dist)
00151 {
00152 for (int i = 0; i < nr_correspondences_result_rej_dist; ++i)
00153 {
00154 EXPECT_EQ ((*correspondences_result_rej_dist)[i].index_query, correspondences_dist[i][0]);
00155 EXPECT_EQ ((*correspondences_result_rej_dist)[i].index_match, correspondences_dist[i][1]);
00156 }
00157 }
00158 }
00159
00161 TEST (PCL, CorrespondenceRejectorMedianDistance)
00162 {
00163 CloudXYZConstPtr source (new CloudXYZ (cloud_source));
00164 CloudXYZConstPtr target (new CloudXYZ (cloud_target));
00165
00166
00167 boost::shared_ptr<pcl::Correspondences> correspondences (new pcl::Correspondences);
00168 pcl::registration::CorrespondenceEstimation<PointXYZ, PointXYZ> corr_est;
00169 corr_est.setInputSource (source);
00170 corr_est.setInputTarget (target);
00171 corr_est.determineCorrespondences (*correspondences);
00172
00173 boost::shared_ptr<pcl::Correspondences> correspondences_result_rej_median_dist (new pcl::Correspondences);
00174 pcl::registration::CorrespondenceRejectorMedianDistance corr_rej_median_dist;
00175 corr_rej_median_dist.setInputCorrespondences(correspondences);
00176 corr_rej_median_dist.setMedianFactor (rej_median_factor);
00177
00178 corr_rej_median_dist.getCorrespondences(*correspondences_result_rej_median_dist);
00179
00180
00181 EXPECT_NEAR (corr_rej_median_dist.getMedianDistance (), rej_median_distance, 1e-4);
00182 EXPECT_EQ (int (correspondences_result_rej_median_dist->size ()), nr_correspondences_result_rej_median_dist);
00183 if (int (correspondences_result_rej_median_dist->size ()) == nr_correspondences_result_rej_median_dist)
00184 {
00185 for (int i = 0; i < nr_correspondences_result_rej_median_dist; ++i)
00186 {
00187 EXPECT_EQ ((*correspondences_result_rej_median_dist)[i].index_query, correspondences_median_dist[i][0]);
00188 EXPECT_EQ ((*correspondences_result_rej_median_dist)[i].index_match, correspondences_median_dist[i][1]);
00189 }
00190 }
00191 }
00192
00194 TEST (PCL, CorrespondenceRejectorOneToOne)
00195 {
00196 CloudXYZConstPtr source (new CloudXYZ (cloud_source));
00197 CloudXYZConstPtr target (new CloudXYZ (cloud_target));
00198
00199
00200 boost::shared_ptr<pcl::Correspondences> correspondences (new pcl::Correspondences);
00201 pcl::registration::CorrespondenceEstimation<PointXYZ, PointXYZ> corr_est;
00202 corr_est.setInputSource (source);
00203 corr_est.setInputTarget (target);
00204 corr_est.determineCorrespondences (*correspondences);
00205
00206 boost::shared_ptr<pcl::Correspondences> correspondences_result_rej_one_to_one (new pcl::Correspondences);
00207 pcl::registration::CorrespondenceRejectorOneToOne corr_rej_one_to_one;
00208 corr_rej_one_to_one.setInputCorrespondences(correspondences);
00209 corr_rej_one_to_one.getCorrespondences(*correspondences_result_rej_one_to_one);
00210
00211
00212 EXPECT_EQ (int (correspondences_result_rej_one_to_one->size ()), nr_correspondences_result_rej_one_to_one);
00213 if (int (correspondences_result_rej_one_to_one->size ()) == nr_correspondences_result_rej_one_to_one)
00214 {
00215 for (int i = 0; i < nr_correspondences_result_rej_one_to_one; ++i)
00216 {
00217 EXPECT_EQ ((*correspondences_result_rej_one_to_one)[i].index_query, correspondences_one_to_one[i][0]);
00218 EXPECT_EQ ((*correspondences_result_rej_one_to_one)[i].index_match, correspondences_one_to_one[i][1]);
00219 }
00220 }
00221 }
00222
00224 TEST (PCL, CorrespondenceRejectorSampleConsensus)
00225 {
00226 CloudXYZConstPtr source (new CloudXYZ (cloud_source));
00227 CloudXYZConstPtr target (new CloudXYZ (cloud_target));
00228
00229
00230 boost::shared_ptr<pcl::Correspondences> correspondences (new pcl::Correspondences);
00231 pcl::registration::CorrespondenceEstimation<PointXYZ, PointXYZ> corr_est;
00232 corr_est.setInputSource (source);
00233 corr_est.setInputTarget (target);
00234 corr_est.determineCorrespondences (*correspondences);
00235 EXPECT_EQ (int (correspondences->size ()), nr_original_correspondences);
00236
00237 boost::shared_ptr<pcl::Correspondences> correspondences_result_rej_sac (new pcl::Correspondences);
00238 pcl::registration::CorrespondenceRejectorSampleConsensus<PointXYZ> corr_rej_sac;
00239 #pragma GCC diagnostic push
00240 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
00241 corr_rej_sac.setInputCloud (source);
00242 source = corr_rej_sac.getInputCloud ();
00243 #pragma GCC diagnostic pop
00244 corr_rej_sac.setInputSource (source);
00245 corr_rej_sac.setInputTarget (target);
00246 corr_rej_sac.setInlierThreshold (rej_sac_max_dist);
00247 corr_rej_sac.setMaximumIterations (rej_sac_max_iter);
00248 corr_rej_sac.setInputCorrespondences (correspondences);
00249 corr_rej_sac.getCorrespondences (*correspondences_result_rej_sac);
00250 Eigen::Matrix4f transform_res_from_SAC = corr_rej_sac.getBestTransformation ();
00251
00252
00253 EXPECT_EQ (int (correspondences_result_rej_sac->size ()), nr_correspondences_result_rej_sac);
00254 if (int (correspondences_result_rej_sac->size ()) == nr_correspondences_result_rej_sac)
00255 {
00256 for (int i = 0; i < nr_correspondences_result_rej_sac; ++i)
00257 {
00258 EXPECT_EQ ((*correspondences_result_rej_sac)[i].index_query, correspondences_sac[i][0]);
00259 EXPECT_EQ ((*correspondences_result_rej_sac)[i].index_match, correspondences_sac[i][1]);
00260 }
00261 }
00262
00263
00264 for (int i = 0; i < 4; ++i)
00265 for (int j = 0; j < 4; ++j)
00266 EXPECT_NEAR (transform_res_from_SAC (i, j), transform_from_SAC[i][j], 1e-4);
00267 }
00268
00270 TEST (PCL, CorrespondenceRejectorSurfaceNormal)
00271 {
00272 CloudXYZConstPtr source (new CloudXYZ (cloud_source));
00273 CloudXYZConstPtr target (new CloudXYZ (cloud_target));
00274
00275
00276 boost::shared_ptr<pcl::Correspondences> correspondences (new pcl::Correspondences);
00277 pcl::registration::CorrespondenceEstimation<PointXYZ, PointXYZ> corr_est;
00278 corr_est.setInputSource (source);
00279 corr_est.setInputTarget (target);
00280 corr_est.determineCorrespondences (*correspondences);
00281
00282
00283 CloudNormalPtr source_normals (new CloudNormal ());
00284 pcl::copyPointCloud (*source, *source_normals);
00285 CloudNormalPtr target_normals (new CloudNormal ());
00286 pcl::copyPointCloud (*target, *target_normals);
00287
00288 pcl::NormalEstimation<PointNormal, PointNormal> norm_est_src;
00289 norm_est_src.setSearchMethod (pcl::search::KdTree<PointNormal>::Ptr (new pcl::search::KdTree<PointNormal>));
00290 norm_est_src.setKSearch (10);
00291 norm_est_src.setInputCloud (source_normals);
00292 norm_est_src.compute (*source_normals);
00293
00294 pcl::NormalEstimation<PointNormal, PointNormal> norm_est_tgt;
00295 norm_est_tgt.setSearchMethod (pcl::search::KdTree<PointNormal>::Ptr (new pcl::search::KdTree<PointNormal>));
00296 norm_est_tgt.setKSearch (10);
00297 norm_est_tgt.setInputCloud (target_normals);
00298 norm_est_tgt.compute (*target_normals);
00299
00300 pcl::registration::CorrespondenceRejectorSurfaceNormal corr_rej_surf_norm;
00301 corr_rej_surf_norm.initializeDataContainer <PointXYZ, PointNormal> ();
00302 corr_rej_surf_norm.setInputSource <PointXYZ> (source);
00303 corr_rej_surf_norm.setInputTarget <PointXYZ> (target);
00304 corr_rej_surf_norm.setInputNormals <PointXYZ, PointNormal> (source_normals);
00305 corr_rej_surf_norm.setTargetNormals <PointXYZ, PointNormal> (target_normals);
00306
00307 boost::shared_ptr<pcl::Correspondences> correspondences_result_rej_surf_norm (new pcl::Correspondences);
00308 corr_rej_surf_norm.setInputCorrespondences (correspondences);
00309 corr_rej_surf_norm.setThreshold (0.5);
00310
00311 corr_rej_surf_norm.getCorrespondences (*correspondences_result_rej_surf_norm);
00312
00313
00314 if (int (correspondences_result_rej_surf_norm->size ()) == nr_correspondences_result_rej_dist)
00315 {
00316 for (int i = 0; i < nr_correspondences_result_rej_dist; ++i)
00317 {
00318 EXPECT_EQ ((*correspondences_result_rej_surf_norm)[i].index_query, correspondences_dist[i][0]);
00319 EXPECT_EQ ((*correspondences_result_rej_surf_norm)[i].index_match, correspondences_dist[i][1]);
00320 }
00321 }
00322 }
00324 TEST (PCL, CorrespondenceRejectorTrimmed)
00325 {
00326 CloudXYZConstPtr source (new CloudXYZ (cloud_source));
00327 CloudXYZConstPtr target (new CloudXYZ (cloud_target));
00328
00329
00330 boost::shared_ptr<pcl::Correspondences> correspondences (new pcl::Correspondences);
00331 pcl::registration::CorrespondenceEstimation<PointXYZ, PointXYZ> corr_est;
00332 corr_est.setInputSource (source);
00333 corr_est.setInputTarget (target);
00334 corr_est.determineCorrespondences (*correspondences);
00335
00336 boost::shared_ptr<pcl::Correspondences> correspondences_result_rej_trimmed (new pcl::Correspondences);
00337 pcl::registration::CorrespondenceRejectorTrimmed corr_rej_trimmed;
00338 corr_rej_trimmed.setOverlapRatio(rej_trimmed_overlap);
00339 corr_rej_trimmed.setInputCorrespondences(correspondences);
00340 corr_rej_trimmed.getCorrespondences(*correspondences_result_rej_trimmed);
00341
00342
00343 EXPECT_EQ (int (correspondences_result_rej_trimmed->size ()), nr_correspondences_result_rej_trimmed);
00344 if (int (correspondences_result_rej_trimmed->size ()) == nr_correspondences_result_rej_trimmed)
00345 {
00346 for (int i = 0; i < nr_correspondences_result_rej_trimmed; ++i)
00347 {
00348 EXPECT_EQ ((*correspondences_result_rej_trimmed)[i].index_query, correspondences_trimmed[i][0]);
00349 EXPECT_EQ ((*correspondences_result_rej_trimmed)[i].index_match, correspondences_trimmed[i][1]);
00350 }
00351 }
00352 }
00353
00355 TEST (PCL, CorrespondenceRejectorVarTrimmed)
00356 {
00357 CloudXYZConstPtr source (new CloudXYZ (cloud_source));
00358 CloudXYZConstPtr target (new CloudXYZ (cloud_target));
00359
00360
00361 boost::shared_ptr<pcl::Correspondences> correspondences (new pcl::Correspondences);
00362 pcl::registration::CorrespondenceEstimation<PointXYZ, PointXYZ> corr_est;
00363 corr_est.setInputSource (source);
00364 corr_est.setInputTarget (target);
00365 corr_est.determineCorrespondences (*correspondences);
00366
00367 boost::shared_ptr<pcl::Correspondences> correspondences_result_rej_var_trimmed_dist (new pcl::Correspondences);
00368 pcl::registration::CorrespondenceRejectorVarTrimmed corr_rej_var_trimmed_dist;
00369 corr_rej_var_trimmed_dist.setInputSource<PointXYZ> (source);
00370 corr_rej_var_trimmed_dist.setInputTarget<PointXYZ> (target);
00371 corr_rej_var_trimmed_dist.setInputCorrespondences(correspondences);
00372
00373 corr_rej_var_trimmed_dist.getCorrespondences(*correspondences_result_rej_var_trimmed_dist);
00374
00375
00376 if (int (correspondences_result_rej_var_trimmed_dist->size ()) == nr_correspondences_result_rej_dist)
00377 {
00378 for (int i = 0; i < nr_correspondences_result_rej_dist; ++i)
00379 {
00380 EXPECT_EQ ((*correspondences_result_rej_var_trimmed_dist)[i].index_query, correspondences_dist[i][0]);
00381 EXPECT_EQ ((*correspondences_result_rej_var_trimmed_dist)[i].index_match, correspondences_dist[i][1]);
00382 }
00383 }
00384 }
00385
00387 TEST (PCL, TransformationEstimationSVD)
00388 {
00389
00390 CloudXYZConstPtr source (new CloudXYZ (cloud_target));
00391 CloudXYZPtr target (new CloudXYZ ());
00392 pcl::transformPointCloud (*source, *target, T_ref);
00393
00394 Eigen::Matrix4f T_SVD_1;
00395 const pcl::registration::TransformationEstimationSVD<PointXYZ, PointXYZ> trans_est_svd;
00396 trans_est_svd.estimateRigidTransformation(*source, *target, T_SVD_1);
00397
00398 const Eigen::Quaternionf R_SVD_1 (T_SVD_1.topLeftCorner <3, 3> ());
00399 const Eigen::Translation3f t_SVD_1 (T_SVD_1.topRightCorner <3, 1> ());
00400
00401 EXPECT_NEAR (R_SVD_1.x (), R_ref.x (), 1e-6f);
00402 EXPECT_NEAR (R_SVD_1.y (), R_ref.y (), 1e-6f);
00403 EXPECT_NEAR (R_SVD_1.z (), R_ref.z (), 1e-6f);
00404 EXPECT_NEAR (R_SVD_1.w (), R_ref.w (), 1e-6f);
00405
00406 EXPECT_NEAR (t_SVD_1.x (), t_ref.x (), 1e-6f);
00407 EXPECT_NEAR (t_SVD_1.y (), t_ref.y (), 1e-6f);
00408 EXPECT_NEAR (t_SVD_1.z (), t_ref.z (), 1e-6f);
00409
00410
00411 Eigen::Matrix4f T_SVD_2;
00412 pcl::Correspondences corr; corr.reserve (source->size ());
00413 for (int i=0; i<source->size (); ++i) corr.push_back (pcl::Correspondence (i, i, 0.f));
00414 trans_est_svd.estimateRigidTransformation(*source, *target, corr, T_SVD_2);
00415
00416 const Eigen::Quaternionf R_SVD_2 (T_SVD_2.topLeftCorner <3, 3> ());
00417 const Eigen::Translation3f t_SVD_2 (T_SVD_2.topRightCorner <3, 1> ());
00418
00419 EXPECT_FLOAT_EQ (R_SVD_1.x (), R_SVD_2.x ());
00420 EXPECT_FLOAT_EQ (R_SVD_1.y (), R_SVD_2.y ());
00421 EXPECT_FLOAT_EQ (R_SVD_1.z (), R_SVD_2.z ());
00422 EXPECT_FLOAT_EQ (R_SVD_1.w (), R_SVD_2.w ());
00423
00424 EXPECT_FLOAT_EQ (t_SVD_1.x (), t_SVD_2.x ());
00425 EXPECT_FLOAT_EQ (t_SVD_1.y (), t_SVD_2.y ());
00426 EXPECT_FLOAT_EQ (t_SVD_1.z (), t_SVD_2.z ());
00427 }
00428
00430 TEST (PCL, TransformationEstimationPointToPlaneLLS)
00431 {
00432 pcl::registration::TransformationEstimationPointToPlaneLLS<pcl::PointNormal, pcl::PointNormal> transform_estimator;
00433
00434
00435 pcl::PointCloud<pcl::PointNormal>::Ptr src (new pcl::PointCloud<pcl::PointNormal>);
00436 src->height = 1;
00437 src->is_dense = true;
00438 for (float x = -5.0f; x <= 5.0f; x += 0.5f)
00439 for (float y = -5.0f; y <= 5.0f; y += 0.5f)
00440 {
00441 pcl::PointNormal p;
00442 p.x = x;
00443 p.y = y;
00444 p.z = 0.1f * powf (x, 2.0f) + 0.2f * p.x * p.y - 0.3f * y + 1.0f;
00445 float & nx = p.normal[0];
00446 float & ny = p.normal[1];
00447 float & nz = p.normal[2];
00448 nx = -0.2f * p.x - 0.2f;
00449 ny = 0.6f * p.y - 0.2f;
00450 nz = 1.0f;
00451
00452 float magnitude = sqrtf (nx * nx + ny * ny + nz * nz);
00453 nx /= magnitude;
00454 ny /= magnitude;
00455 nz /= magnitude;
00456
00457 src->points.push_back (p);
00458 }
00459 src->width = static_cast<uint32_t> (src->points.size ());
00460
00461
00462 Eigen::Matrix4f ground_truth_tform = Eigen::Matrix4f::Identity ();
00463 ground_truth_tform.row (0) << 0.9938f, 0.0988f, 0.0517f, 0.1000f;
00464 ground_truth_tform.row (1) << -0.0997f, 0.9949f, 0.0149f, -0.2000f;
00465 ground_truth_tform.row (2) << -0.0500f, -0.0200f, 0.9986f, 0.3000f;
00466 ground_truth_tform.row (3) << 0.0000f, 0.0000f, 0.0000f, 1.0000f;
00467
00468 pcl::PointCloud<pcl::PointNormal>::Ptr tgt (new pcl::PointCloud<pcl::PointNormal>);
00469
00470 pcl::transformPointCloudWithNormals (*src, *tgt, ground_truth_tform);
00471
00472 Eigen::Matrix4f estimated_transform;
00473 transform_estimator.estimateRigidTransformation (*src, *tgt, estimated_transform);
00474
00475 for (int i = 0; i < 4; ++i)
00476 for (int j = 0; j < 4; ++j)
00477 EXPECT_NEAR (estimated_transform (i, j), ground_truth_tform (i, j), 1e-2);
00478 }
00479
00481 TEST (PCL, TransformationEstimationLM)
00482 {
00483 CloudXYZConstPtr source (new CloudXYZ (cloud_target));
00484 CloudXYZPtr target (new CloudXYZ ());
00485 pcl::transformPointCloud (*source, *target, T_ref);
00486
00487
00488 Eigen::Matrix4f T_LM_float;
00489 const pcl::registration::TransformationEstimationLM<PointXYZ, PointXYZ, float> trans_est_lm_float;
00490 trans_est_lm_float.estimateRigidTransformation (*source, *target, T_LM_float);
00491
00492 const Eigen::Quaternionf R_LM_1_float (T_LM_float.topLeftCorner <3, 3> ());
00493 const Eigen::Translation3f t_LM_1_float (T_LM_float.topRightCorner <3, 1> ());
00494
00495 EXPECT_NEAR (R_LM_1_float.x (), R_ref.x (), 1e-4f);
00496 EXPECT_NEAR (R_LM_1_float.y (), R_ref.y (), 1e-4f);
00497 EXPECT_NEAR (R_LM_1_float.z (), R_ref.z (), 1e-4f);
00498 EXPECT_NEAR (R_LM_1_float.w (), R_ref.w (), 1e-4f);
00499
00500 EXPECT_NEAR (t_LM_1_float.x (), t_ref.x (), 1e-3f);
00501 EXPECT_NEAR (t_LM_1_float.y (), t_ref.y (), 1e-3f);
00502 EXPECT_NEAR (t_LM_1_float.z (), t_ref.z (), 1e-3f);
00503
00504
00505 Eigen::Matrix4f T_LM_2_float;
00506 pcl::Correspondences corr;
00507 corr.reserve (source->size ());
00508 for (int i = 0; i < source->size (); ++i)
00509 corr.push_back (pcl::Correspondence (i, i, 0.f));
00510 trans_est_lm_float.estimateRigidTransformation (*source, *target, corr, T_LM_2_float);
00511
00512 const Eigen::Quaternionf R_LM_2_float (T_LM_2_float.topLeftCorner <3, 3> ());
00513 const Eigen::Translation3f t_LM_2_float (T_LM_2_float.topRightCorner <3, 1> ());
00514
00515 EXPECT_FLOAT_EQ (R_LM_1_float.x (), R_LM_2_float.x ());
00516 EXPECT_FLOAT_EQ (R_LM_1_float.y (), R_LM_2_float.y ());
00517 EXPECT_FLOAT_EQ (R_LM_1_float.z (), R_LM_2_float.z ());
00518 EXPECT_FLOAT_EQ (R_LM_1_float.w (), R_LM_2_float.w ());
00519
00520 EXPECT_FLOAT_EQ (t_LM_1_float.x (), t_LM_2_float.x ());
00521 EXPECT_FLOAT_EQ (t_LM_1_float.y (), t_LM_2_float.y ());
00522 EXPECT_FLOAT_EQ (t_LM_1_float.z (), t_LM_2_float.z ());
00523
00524
00525
00526 Eigen::Matrix4d T_LM_double;
00527 const pcl::registration::TransformationEstimationLM<PointXYZ, PointXYZ, double> trans_est_lm_double;
00528 trans_est_lm_double.estimateRigidTransformation (*source, *target, T_LM_double);
00529
00530 const Eigen::Quaterniond R_LM_1_double (T_LM_double.topLeftCorner <3, 3> ());
00531 const Eigen::Translation3d t_LM_1_double (T_LM_double.topRightCorner <3, 1> ());
00532
00533 EXPECT_NEAR (R_LM_1_double.x (), R_ref.x (), 1e-6);
00534 EXPECT_NEAR (R_LM_1_double.y (), R_ref.y (), 1e-6);
00535 EXPECT_NEAR (R_LM_1_double.z (), R_ref.z (), 1e-6);
00536 EXPECT_NEAR (R_LM_1_double.w (), R_ref.w (), 1e-6);
00537
00538 EXPECT_NEAR (t_LM_1_double.x (), t_ref.x (), 1e-6);
00539 EXPECT_NEAR (t_LM_1_double.y (), t_ref.y (), 1e-6);
00540 EXPECT_NEAR (t_LM_1_double.z (), t_ref.z (), 1e-6);
00541
00542
00543 Eigen::Matrix4d T_LM_2_double;
00544 corr.clear ();
00545 corr.reserve (source->size ());
00546 for (int i = 0; i < source->size (); ++i)
00547 corr.push_back (pcl::Correspondence (i, i, 0.f));
00548 trans_est_lm_double.estimateRigidTransformation (*source, *target, corr, T_LM_2_double);
00549
00550 const Eigen::Quaterniond R_LM_2_double (T_LM_2_double.topLeftCorner <3, 3> ());
00551 const Eigen::Translation3d t_LM_2_double (T_LM_2_double.topRightCorner <3, 1> ());
00552
00553 EXPECT_DOUBLE_EQ (R_LM_1_double.x (), R_LM_2_double.x ());
00554 EXPECT_DOUBLE_EQ (R_LM_1_double.y (), R_LM_2_double.y ());
00555 EXPECT_DOUBLE_EQ (R_LM_1_double.z (), R_LM_2_double.z ());
00556 EXPECT_DOUBLE_EQ (R_LM_1_double.w (), R_LM_2_double.w ());
00557
00558 EXPECT_DOUBLE_EQ (t_LM_1_double.x (), t_LM_2_double.x ());
00559 EXPECT_DOUBLE_EQ (t_LM_1_double.y (), t_LM_2_double.y ());
00560 EXPECT_DOUBLE_EQ (t_LM_1_double.z (), t_LM_2_double.z ());
00561 }
00562
00564 TEST (PCL, TransformationEstimationPointToPlane)
00565 {
00566 pcl::registration::TransformationEstimationPointToPlane<pcl::PointNormal, pcl::PointNormal, float> transform_estimator_float;
00567
00568
00569 pcl::PointCloud<pcl::PointNormal>::Ptr src (new pcl::PointCloud<pcl::PointNormal>);
00570 src->height = 1;
00571 src->is_dense = true;
00572 for (float x = -5.0f; x <= 5.0f; x += 0.5f)
00573 for (float y = -5.0f; y <= 5.0f; y += 0.5f)
00574 {
00575 pcl::PointNormal p;
00576 p.x = x;
00577 p.y = y;
00578 p.z = 0.1f * powf (x, 2.0f) + 0.2f * p.x * p.y - 0.3f * y + 1.0f;
00579 float & nx = p.normal[0];
00580 float & ny = p.normal[1];
00581 float & nz = p.normal[2];
00582 nx = -0.2f * p.x - 0.2f;
00583 ny = 0.6f * p.y - 0.2f;
00584 nz = 1.0f;
00585
00586 float magnitude = sqrtf (nx * nx + ny * ny + nz * nz);
00587 nx /= magnitude;
00588 ny /= magnitude;
00589 nz /= magnitude;
00590
00591 src->points.push_back (p);
00592 }
00593 src->width = static_cast<uint32_t> (src->points.size ());
00594
00595
00596 Eigen::Matrix4f ground_truth_tform = Eigen::Matrix4f::Identity ();
00597 ground_truth_tform.row (0) << 0.9938f, 0.0988f, 0.0517f, 0.1000f;
00598 ground_truth_tform.row (1) << -0.0997f, 0.9949f, 0.0149f, -0.2000f;
00599 ground_truth_tform.row (2) << -0.0500f, -0.0200f, 0.9986f, 0.3000f;
00600 ground_truth_tform.row (3) << 0.0000f, 0.0000f, 0.0000f, 1.0000f;
00601
00602 pcl::PointCloud<pcl::PointNormal>::Ptr tgt (new pcl::PointCloud<pcl::PointNormal>);
00603
00604 pcl::transformPointCloudWithNormals (*src, *tgt, ground_truth_tform);
00605
00606 Eigen::Matrix4f estimated_transform_float;
00607 transform_estimator_float.estimateRigidTransformation (*src, *tgt, estimated_transform_float);
00608
00609 for (int i = 0; i < 4; ++i)
00610 for (int j = 0; j < 4; ++j)
00611 EXPECT_NEAR (estimated_transform_float (i, j), ground_truth_tform (i, j), 1e-3);
00612
00613
00614
00615 pcl::registration::TransformationEstimationPointToPlane<pcl::PointNormal, pcl::PointNormal, double> transform_estimator_double;
00616 Eigen::Matrix4d estimated_transform_double;
00617 transform_estimator_double.estimateRigidTransformation (*src, *tgt, estimated_transform_double);
00618
00619 for (int i = 0; i < 4; ++i)
00620 for (int j = 0; j < 4; ++j)
00621 EXPECT_NEAR (estimated_transform_double (i, j), ground_truth_tform (i, j), 1e-3);
00622 }
00623
00624
00625
00626
00627 int
00628 main (int argc, char** argv)
00629 {
00630 if (argc < 3)
00631 {
00632 std::cerr << "No test files given. Please download `bun0.pcd` and `bun4.pcd` and pass their path to the test." << std::endl;
00633 return (-1);
00634 }
00635
00636
00637 if (pcl::io::loadPCDFile (argv[1], cloud_source) < 0)
00638 {
00639 std::cerr << "Failed to read test file. Please download `bun0.pcd` and pass its path to the test." << std::endl;
00640 return (-1);
00641 }
00642 if (pcl::io::loadPCDFile (argv[2], cloud_target) < 0)
00643 {
00644 std::cerr << "Failed to read test file. Please download `bun4.pcd` and pass its path to the test." << std::endl;
00645 return (-1);
00646 }
00647
00648 testing::InitGoogleTest (&argc, argv);
00649 return (RUN_ALL_TESTS ());
00650
00651
00652
00653
00654
00655
00656 }
00657