test_registration_api.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Point Cloud Library (PCL) - www.pointclouds.org
00005  *  Copyright (c) 2010-2011, Willow Garage, Inc.
00006  *
00007  *  All rights reserved.
00008  *
00009  *  Redistribution and use in source and binary forms, with or without
00010  *  modification, are permitted provided that the following conditions
00011  *  are met:
00012  *
00013  *   * Redistributions of source code must retain the above copyright
00014  *     notice, this list of conditions and the following disclaimer.
00015  *   * Redistributions in binary form must reproduce the above
00016  *     copyright notice, this list of conditions and the following
00017  *     disclaimer in the documentation and/or other materials provided
00018  *     with the distribution.
00019  *   * Neither the name of the copyright holder(s) nor the names of its
00020  *     contributors may be used to endorse or promote products derived
00021  *     from this software without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  * $Id$
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   // check for correct order and number of matches
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   // check for correct matches and number of matches
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   // re-do correspondence estimation
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);        // test for PCL_DEPRECATED
00136   source = corr_est.getInputCloud ();     // test for PCL_DEPRECATED
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   // check for correct matches and number of matches
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   // re-do correspondence estimation
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   // check for correct matches
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   // re-do correspondence estimation
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   // check for correct matches and number of matches
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   // re-do correspondence estimation
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);        // test for PCL_DEPRECATED
00242   source = corr_rej_sac.getInputCloud ();     // test for PCL_DEPRECATED
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   // check for correct matches and number of matches
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   // check for correct transformation
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   // re-do correspondence estimation
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   // check for correct matches
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   // re-do correspondence estimation
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   // check for correct matches, number of matches, and for sorting (correspondences should be sorted w.r.t. distance)
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   // re-do correspondence estimation
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   // check for correct matches
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   // Ideal conditions for the estimation (no noise, exact correspondences)
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   // Check if the estimation with correspondences gives the same results
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   // Create a test cloud
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   // Create a test matrix
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   // Test the float precision first
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   // Check if the estimation with correspondences gives the same results
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   // Test the double precision, notice that the testing tolerances are much smaller
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   // Check if the estimation with correspondences gives the same results
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   // Create a test cloud
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   // Create a test matrix
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   // Input
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   // Tranpose the cloud_model
00652   /*for (size_t i = 0; i < cloud_model.points.size (); ++i)
00653   {
00654   //  cloud_model.points[i].z += 1;
00655   }*/
00656 }
00657 /* ]--- */


pcl
Author(s): Open Perception
autogenerated on Wed Aug 26 2015 15:35:48