test_registration.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 Willow Garage, Inc. 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: test_registration.cpp 5124 2012-03-16 03:09:41Z rusu $
00037  *
00038  */
00039 
00040 #include <gtest/gtest.h>
00041 
00042 #include <pcl/point_types.h>
00043 #include <pcl/io/pcd_io.h>
00044 #include <pcl/features/normal_3d.h>
00045 #include <pcl/features/fpfh.h>
00046 #include <pcl/registration/registration.h>
00047 #include <pcl/registration/icp.h>
00048 #include <pcl/registration/icp_nl.h>
00049 #include <pcl/registration/transformation_estimation_point_to_plane.h>
00050 #include <pcl/registration/transformation_validation_euclidean.h>
00051 #include <pcl/registration/transformation_estimation_point_to_plane_lls.h>
00052 #include <pcl/registration/ia_ransac.h>
00053 #include <pcl/registration/pyramid_feature_matching.h>
00054 #include <pcl/features/ppf.h>
00055 #include <pcl/registration/ppf_registration.h>
00056 // We need Histogram<2> to function, so we'll explicitely add kdtree_flann.hpp here
00057 #include <pcl/kdtree/impl/kdtree_flann.hpp>
00058 //(pcl::Histogram<2>)
00059 
00060 using namespace pcl;
00061 using namespace pcl::io;
00062 using namespace std;
00063 
00064 PointCloud<PointXYZ> cloud_source, cloud_target, cloud_reg;
00065 
00066 template <typename PointSource, typename PointTarget>
00067 class RegistrationWrapper : public Registration<PointSource, PointTarget>
00068 {
00069 public:
00070   void computeTransformation (pcl::PointCloud<PointSource> &, const Eigen::Matrix4f& ) { }
00071 
00072   bool hasValidFeaturesTest ()
00073   {
00074     return (this->hasValidFeatures ());
00075   }
00076   void findFeatureCorrespondencesTest (int index, std::vector<int> &correspondence_indices)
00077   {
00078     this->findFeatureCorrespondences (index, correspondence_indices);
00079   }
00080 };
00081 
00083 TEST (PCL, findFeatureCorrespondences)
00084 {
00085   typedef Histogram<2> FeatureT;
00086   typedef PointCloud<FeatureT> FeatureCloud;
00087   typedef FeatureCloud::ConstPtr FeatureCloudConstPtr;
00088 
00089   RegistrationWrapper <PointXYZ, PointXYZ> reg;
00090 
00091   FeatureCloud feature0, feature1, feature2, feature3;
00092   feature0.height = feature1.height = feature2.height = feature3.height = 1;
00093   feature0.is_dense = feature1.is_dense = feature2.is_dense = feature3.is_dense = true;
00094 
00095   for (float x = -5.0f; x <= 5.0f; x += 0.2f)
00096   {
00097     for (float y = -5.0f; y <= 5.0f; y += 0.2f)
00098     {
00099       FeatureT f;
00100       f.histogram[0] = x;
00101       f.histogram[1] = y;
00102       feature0.points.push_back (f);
00103 
00104       f.histogram[0] = x;
00105       f.histogram[1] = y - 2.5f;
00106       feature1.points.push_back (f);
00107 
00108       f.histogram[0] = x - 2.0f;
00109       f.histogram[1] = y + 1.5f;
00110       feature2.points.push_back (f);
00111 
00112       f.histogram[0] = x + 2.0f;
00113       f.histogram[1] = y + 1.5f;
00114       feature3.points.push_back (f);
00115     }
00116   }
00117   feature0.width = static_cast<uint32_t> (feature0.points.size ());
00118   feature1.width = static_cast<uint32_t> (feature1.points.size ());
00119   feature2.width = static_cast<uint32_t> (feature2.points.size ());
00120   feature3.width = static_cast<uint32_t> (feature3.points.size ());
00121 
00122   KdTreeFLANN<FeatureT> tree;
00123 
00124 /*  int k = 600;
00125 
00126   reg.setSourceFeature<FeatureT> (feature0.makeShared (), "feature1");
00127   reg.setTargetFeature<FeatureT> (feature1.makeShared (), "feature1");
00128   reg.setKSearch<FeatureT> (tree.makeShared (), k, "feature1");
00129 
00130   reg.setSourceFeature<FeatureT> (feature0.makeShared (), "feature2");
00131   reg.setTargetFeature<FeatureT> (feature2.makeShared (), "feature2");
00132   reg.setKSearch<FeatureT> (tree.makeShared (), k, "feature2");
00133 
00134   reg.setSourceFeature<FeatureT> (feature0.makeShared (), "feature3");
00135   reg.setTargetFeature<FeatureT> (feature3.makeShared (), "feature3");
00136   reg.setKSearch<FeatureT> (tree.makeShared (), k, "feature3");
00137 
00138   ASSERT_TRUE (reg.hasValidFeaturesTest ());
00139 
00140   std::vector<int> indices;
00141   reg.findFeatureCorrespondencesTest (1300, indices);
00142 
00143   ASSERT_EQ ((int)indices.size (), 10);
00144   const int correct_values[] = {1197, 1248, 1249, 1299, 1300, 1301, 1302, 1350, 1351, 1401};
00145   for (size_t i = 0; i < indices.size (); ++i)
00146   {
00147     EXPECT_EQ (indices[i], correct_values[i]);
00148   }
00149 */
00150 }
00151 
00153 TEST (PCL, IterativeClosestPoint)
00154 {
00155   IterativeClosestPoint<PointXYZ, PointXYZ> reg;
00156   reg.setInputCloud (cloud_source.makeShared ());
00157   reg.setInputTarget (cloud_target.makeShared ());
00158   reg.setMaximumIterations (50);
00159   reg.setTransformationEpsilon (1e-8);
00160   reg.setMaxCorrespondenceDistance (0.05);
00161 
00162   // Register
00163   reg.align (cloud_reg);
00164   EXPECT_EQ (int (cloud_reg.points.size ()), int (cloud_source.points.size ()));
00165 
00166   Eigen::Matrix4f transformation = reg.getFinalTransformation ();
00167 
00168   EXPECT_NEAR (transformation (0, 0), 0.8806,  1e-3);
00169   EXPECT_NEAR (transformation (0, 1), 0.036481287330389023, 1e-2);
00170   EXPECT_NEAR (transformation (0, 2), -0.4724, 1e-3);
00171   EXPECT_NEAR (transformation (0, 3), 0.03453, 1e-3);
00172 
00173   EXPECT_NEAR (transformation (1, 0), -0.02354,  1e-3);
00174   EXPECT_NEAR (transformation (1, 1),  0.9992,   1e-3);
00175   EXPECT_NEAR (transformation (1, 2),  0.03326,  1e-3);
00176   EXPECT_NEAR (transformation (1, 3), -0.001519, 1e-3);
00177 
00178   EXPECT_NEAR (transformation (2, 0),  0.4732,  1e-3);
00179   EXPECT_NEAR (transformation (2, 1), -0.01817, 1e-3);
00180   EXPECT_NEAR (transformation (2, 2),  0.8808,  1e-3);
00181   EXPECT_NEAR (transformation (2, 3),  0.04116, 1e-3);
00182 
00183   EXPECT_EQ (transformation (3, 0), 0);
00184   EXPECT_EQ (transformation (3, 1), 0);
00185   EXPECT_EQ (transformation (3, 2), 0);
00186   EXPECT_EQ (transformation (3, 3), 1);
00187 }
00188 
00190 TEST (PCL, IterativeClosestPointNonLinear)
00191 {
00192   typedef PointXYZRGB PointT;
00193   PointCloud<PointT>::Ptr temp_src (new PointCloud<PointT>);
00194   copyPointCloud (cloud_source, *temp_src);
00195   PointCloud<PointT>::Ptr temp_tgt (new PointCloud<PointT>);
00196   copyPointCloud (cloud_target, *temp_tgt);
00197   PointCloud<PointT> output;
00198 
00199   IterativeClosestPointNonLinear<PointT, PointT> reg;
00200   reg.setInputCloud (temp_src);
00201   reg.setInputTarget (temp_tgt);
00202   reg.setMaximumIterations (50);
00203   reg.setTransformationEpsilon (1e-8);
00204 
00205   // Register
00206   reg.align (output);
00207   EXPECT_EQ (int (output.points.size ()), int (cloud_source.points.size ()));
00208 
00209   // We get different results on 32 vs 64-bit systems.  To address this, we've removed the explicit output test
00210   // on the transformation matrix.  Instead, we're testing to make sure the algorithm converges to a sufficiently
00211   // low error by checking the fitness score.
00212   /*
00213   Eigen::Matrix4f transformation = reg.getFinalTransformation ();
00214 
00215   EXPECT_NEAR (transformation (0, 0),  0.941755, 1e-2);
00216   EXPECT_NEAR (transformation (0, 1),  0.147362, 1e-2);
00217   EXPECT_NEAR (transformation (0, 2), -0.281285, 1e-2);
00218   EXPECT_NEAR (transformation (0, 3),  0.029813, 1e-2);
00219 
00220   EXPECT_NEAR (transformation (1, 0), -0.111655, 1e-2);
00221   EXPECT_NEAR (transformation (1, 1),  0.990408, 1e-2);
00222   EXPECT_NEAR (transformation (1, 2),  0.139090, 1e-2);
00223   EXPECT_NEAR (transformation (1, 3), -0.001864, 1e-2);
00224 
00225   EXPECT_NEAR (transformation (2, 0),  0.297271, 1e-2);
00226   EXPECT_NEAR (transformation (2, 1), -0.092015, 1e-2);
00227   EXPECT_NEAR (transformation (2, 2),  0.939670, 1e-2);
00228   EXPECT_NEAR (transformation (2, 3),  0.042721, 1e-2);
00229 
00230   EXPECT_EQ (transformation (3, 0), 0);
00231   EXPECT_EQ (transformation (3, 1), 0);
00232   EXPECT_EQ (transformation (3, 2), 0);
00233   EXPECT_EQ (transformation (3, 3), 1);
00234   */
00235   EXPECT_LT (reg.getFitnessScore (), 0.001);
00236 }
00237 
00239 TEST (PCL, IterativeClosestPoint_PointToPlane)
00240 {
00241   typedef PointNormal PointT;
00242   PointCloud<PointT>::Ptr src (new PointCloud<PointT>);
00243   copyPointCloud (cloud_source, *src);
00244   PointCloud<PointT>::Ptr tgt (new PointCloud<PointT>);
00245   copyPointCloud (cloud_target, *tgt);
00246   PointCloud<PointT> output;
00247 
00248   NormalEstimation<PointNormal, PointNormal> norm_est;
00249   norm_est.setSearchMethod (search::KdTree<PointNormal>::Ptr (new search::KdTree<PointNormal>));
00250   norm_est.setKSearch (10);
00251   norm_est.setInputCloud (tgt);
00252   norm_est.compute (*tgt);
00253 
00254   IterativeClosestPoint<PointT, PointT> reg;
00255   typedef registration::TransformationEstimationPointToPlane<PointT, PointT> PointToPlane;
00256   boost::shared_ptr<PointToPlane> point_to_plane (new PointToPlane);
00257   reg.setTransformationEstimation (point_to_plane);
00258   reg.setInputCloud (src);
00259   reg.setInputTarget (tgt);
00260   reg.setMaximumIterations (50);
00261   reg.setTransformationEpsilon (1e-8);
00262 
00263   // Register
00264   reg.align (output);
00265   EXPECT_EQ (int (output.points.size ()), int (cloud_source.points.size ()));
00266 
00267   // We get different results on 32 vs 64-bit systems.  To address this, we've removed the explicit output test
00268   // on the transformation matrix.  Instead, we're testing to make sure the algorithm converges to a sufficiently
00269   // low error by checking the fitness score.
00270   /*
00271   Eigen::Matrix4f transformation = reg.getFinalTransformation ();
00272 
00273   EXPECT_NEAR (transformation (0, 0),  0.9046, 1e-2);
00274   EXPECT_NEAR (transformation (0, 1),  0.0609, 1e-2);
00275   EXPECT_NEAR (transformation (0, 2), -0.4219, 1e-2);
00276   EXPECT_NEAR (transformation (0, 3),  0.0327, 1e-2);
00277 
00278   EXPECT_NEAR (transformation (1, 0), -0.0328, 1e-2);
00279   EXPECT_NEAR (transformation (1, 1),  0.9968, 1e-2);
00280   EXPECT_NEAR (transformation (1, 2),  0.0851, 1e-2);
00281   EXPECT_NEAR (transformation (1, 3), -0.0003, 1e-2);
00282 
00283   EXPECT_NEAR (transformation (2, 0),  0.4250, 1e-2);
00284   EXPECT_NEAR (transformation (2, 1), -0.0641, 1e-2);
00285   EXPECT_NEAR (transformation (2, 2),  0.9037, 1e-2);
00286   EXPECT_NEAR (transformation (2, 3),  0.0413, 1e-2);
00287 
00288   EXPECT_EQ (transformation (3, 0), 0);
00289   EXPECT_EQ (transformation (3, 1), 0);
00290   EXPECT_EQ (transformation (3, 2), 0);
00291   EXPECT_EQ (transformation (3, 3), 1);
00292   */
00293   EXPECT_LT (reg.getFitnessScore (), 0.001);
00294 }
00295 
00297 TEST (PCL, TransformationEstimationPointToPlaneLLS)
00298 {
00299   registration::TransformationEstimationPointToPlaneLLS<PointNormal, PointNormal> tform_est;
00300 
00301   // Create a test cloud
00302   PointCloud<PointNormal>::Ptr src (new PointCloud<PointNormal>);
00303   src->height = 1;
00304   src->is_dense = true;
00305   for (float x = -5.0f; x <= 5.0f; x += 0.5f)
00306   {
00307     for (float y = -5.0f; y <= 5.0f; y += 0.5f)
00308     {
00309       PointNormal p;
00310       p.x = x;
00311       p.y = y;
00312       p.z = 0.1f * powf (x, 2.0f) + 0.2f * p.x * p.y - 0.3f * y + 1.0f;
00313       float & nx = p.normal[0];
00314       float & ny = p.normal[1];
00315       float & nz = p.normal[2];
00316       nx = -0.2f * p.x - 0.2f;
00317       ny = 0.6f * p.y - 0.2f;
00318       nz = 1.0f;
00319 
00320       float magnitude = sqrtf (nx * nx + ny * ny + nz * nz);
00321       nx /= magnitude;
00322       ny /= magnitude;
00323       nz /= magnitude;
00324 
00325       src->points.push_back (p);
00326     }
00327   }
00328   src->width = static_cast<uint32_t> (src->points.size ());
00329 
00330   // Create a test matrix
00331   Eigen::Matrix4f ground_truth_tform = Eigen::Matrix4f::Identity ();
00332   ground_truth_tform.row (0) <<  0.9938f,  0.0988f,  0.0517f,  0.1000f;
00333   ground_truth_tform.row (1) << -0.0997f,  0.9949f,  0.0149f, -0.2000f;
00334   ground_truth_tform.row (2) << -0.0500f, -0.0200f,  0.9986f,  0.3000f;
00335   ground_truth_tform.row (3) <<  0.0000f,  0.0000f,  0.0000f,  1.0000f;
00336 
00337   PointCloud<PointNormal>::Ptr tgt (new PointCloud<PointNormal>);
00338 
00339   transformPointCloudWithNormals (*src, *tgt, ground_truth_tform);
00340 
00341   Eigen::Matrix4f estimated_tform;
00342   tform_est.estimateRigidTransformation (*src, *tgt, estimated_tform);
00343 
00344   for (int i = 0; i < 4; ++i)
00345     for (int j = 0; j < 4; ++j)
00346       EXPECT_NEAR (estimated_tform (i, j), ground_truth_tform (i, j), 1e-2);
00347 }
00348 
00350 TEST (PCL, SampleConsensusInitialAlignment)
00351 {
00352   // Transform the source cloud by a large amount
00353   Eigen::Vector3f initial_offset (100, 0, 0);
00354   float angle = static_cast<float> (M_PI) / 2.0f;
00355   Eigen::Quaternionf initial_rotation (cos (angle / 2), 0, 0, sin (angle / 2));
00356   PointCloud<PointXYZ> cloud_source_transformed;
00357   transformPointCloud (cloud_source, cloud_source_transformed, initial_offset, initial_rotation);
00358 
00359   // Create shared pointers
00360   PointCloud<PointXYZ>::Ptr cloud_source_ptr, cloud_target_ptr;
00361   cloud_source_ptr = cloud_source_transformed.makeShared ();
00362   cloud_target_ptr = cloud_target.makeShared ();
00363 
00364   // Initialize estimators for surface normals and FPFH features
00365   search::KdTree<PointXYZ>::Ptr tree (new search::KdTree<PointXYZ>);
00366 
00367   NormalEstimation<PointXYZ, Normal> norm_est;
00368   norm_est.setSearchMethod (tree);
00369   norm_est.setRadiusSearch (0.05);
00370   PointCloud<Normal> normals;
00371 
00372   FPFHEstimation<PointXYZ, Normal, FPFHSignature33> fpfh_est;
00373   fpfh_est.setSearchMethod (tree);
00374   fpfh_est.setRadiusSearch (0.05);
00375   PointCloud<FPFHSignature33> features_source, features_target;
00376 
00377   // Estimate the FPFH features for the source cloud
00378   norm_est.setInputCloud (cloud_source_ptr);
00379   norm_est.compute (normals);
00380   fpfh_est.setInputCloud (cloud_source_ptr);
00381   fpfh_est.setInputNormals (normals.makeShared ());
00382   fpfh_est.compute (features_source);
00383 
00384   // Estimate the FPFH features for the target cloud
00385   norm_est.setInputCloud (cloud_target_ptr);
00386   norm_est.compute (normals);
00387   fpfh_est.setInputCloud (cloud_target_ptr);
00388   fpfh_est.setInputNormals (normals.makeShared ());
00389   fpfh_est.compute (features_target);
00390 
00391   // Initialize Sample Consensus Initial Alignment (SAC-IA)
00392   SampleConsensusInitialAlignment<PointXYZ, PointXYZ, FPFHSignature33> reg;
00393   reg.setMinSampleDistance (0.05f);
00394   reg.setMaxCorrespondenceDistance (0.2);
00395   reg.setMaximumIterations (1000);
00396 
00397   reg.setInputCloud (cloud_source_ptr);
00398   reg.setInputTarget (cloud_target_ptr);
00399   reg.setSourceFeatures (features_source.makeShared ());
00400   reg.setTargetFeatures (features_target.makeShared ());
00401 
00402   // Register
00403   reg.align (cloud_reg);
00404   EXPECT_EQ (int (cloud_reg.points.size ()), int (cloud_source.points.size ()));
00405   EXPECT_EQ (reg.getFitnessScore () < 0.0005, true);
00406 }
00407 
00409 TEST (PCL, PyramidFeatureHistogram)
00410 {
00411   // Create shared pointers
00412    PointCloud<PointXYZ>::Ptr cloud_source_ptr = cloud_source.makeShared (),
00413        cloud_target_ptr = cloud_target.makeShared ();
00414 
00415   PointCloud<Normal>::Ptr cloud_source_normals (new PointCloud<Normal> ()),
00416       cloud_target_normals (new PointCloud<Normal> ());
00417   search::KdTree<PointXYZ>::Ptr tree (new search::KdTree<PointXYZ>);
00418   NormalEstimation<PointXYZ, Normal> normal_estimator;
00419   normal_estimator.setSearchMethod (tree);
00420   normal_estimator.setRadiusSearch (0.05);
00421   normal_estimator.setInputCloud (cloud_source_ptr);
00422   normal_estimator.compute (*cloud_source_normals);
00423 
00424   normal_estimator.setInputCloud (cloud_target_ptr);
00425   normal_estimator.compute (*cloud_target_normals);
00426 
00427 
00428   PointCloud<PPFSignature>::Ptr ppf_signature_source (new PointCloud<PPFSignature> ()),
00429       ppf_signature_target (new PointCloud<PPFSignature> ());
00430   PPFEstimation<PointXYZ, Normal, PPFSignature> ppf_estimator;
00431   ppf_estimator.setInputCloud (cloud_source_ptr);
00432   ppf_estimator.setInputNormals (cloud_source_normals);
00433   ppf_estimator.compute (*ppf_signature_source);
00434 
00435   ppf_estimator.setInputCloud (cloud_target_ptr);
00436   ppf_estimator.setInputNormals (cloud_target_normals);
00437   ppf_estimator.compute (*ppf_signature_target);
00438 
00439 
00440   vector<pair<float, float> > dim_range_input, dim_range_target;
00441   for (size_t i = 0; i < 3; ++i) dim_range_input.push_back (pair<float, float> (static_cast<float> (-M_PI), static_cast<float> (M_PI)));
00442   dim_range_input.push_back (pair<float, float> (0.0f, 1.0f));
00443   for (size_t i = 0; i < 3; ++i) dim_range_target.push_back (pair<float, float> (static_cast<float> (-M_PI) * 10.0f, static_cast<float> (M_PI) * 10.0f));
00444   dim_range_target.push_back (pair<float, float> (0.0f, 50.0f));
00445 
00446 
00447   PyramidFeatureHistogram<PPFSignature>::Ptr pyramid_source (new PyramidFeatureHistogram<PPFSignature> ()),
00448       pyramid_target (new PyramidFeatureHistogram<PPFSignature> ());
00449   pyramid_source->setInputCloud (ppf_signature_source);
00450   pyramid_source->setInputDimensionRange (dim_range_input);
00451   pyramid_source->setTargetDimensionRange (dim_range_target);
00452   pyramid_source->compute ();
00453 
00454   pyramid_target->setInputCloud (ppf_signature_target);
00455   pyramid_target->setInputDimensionRange (dim_range_input);
00456   pyramid_target->setTargetDimensionRange (dim_range_target);
00457   pyramid_target->compute ();
00458 
00459   float similarity_value = PyramidFeatureHistogram<PPFSignature>::comparePyramidFeatureHistograms (pyramid_source, pyramid_target);
00460   EXPECT_NEAR (similarity_value, 0.74101555347442627, 1e-4);
00461 
00462   vector<pair<float, float> > dim_range_target2;
00463   for (size_t i = 0; i < 3; ++i) dim_range_target2.push_back (pair<float, float> (static_cast<float> (-M_PI) * 5.0f, static_cast<float> (M_PI) * 5.0f));
00464     dim_range_target2.push_back (pair<float, float> (0.0f, 20.0f));
00465 
00466   pyramid_source->setTargetDimensionRange (dim_range_target2);
00467   pyramid_source->compute ();
00468 
00469   pyramid_target->setTargetDimensionRange (dim_range_target2);
00470   pyramid_target->compute ();
00471 
00472   float similarity_value2 = PyramidFeatureHistogram<PPFSignature>::comparePyramidFeatureHistograms (pyramid_source, pyramid_target);
00473   EXPECT_NEAR (similarity_value2, 0.80097091197967529, 1e-4);
00474 
00475 
00476   vector<pair<float, float> > dim_range_target3;
00477   for (size_t i = 0; i < 3; ++i) dim_range_target3.push_back (pair<float, float> (static_cast<float> (-M_PI) * 2.0f, static_cast<float> (M_PI) * 2.0f));
00478   dim_range_target3.push_back (pair<float, float> (0.0f, 10.0f));
00479 
00480   pyramid_source->setTargetDimensionRange (dim_range_target3);
00481   pyramid_source->compute ();
00482 
00483   pyramid_target->setTargetDimensionRange (dim_range_target3);
00484   pyramid_target->compute ();
00485 
00486   float similarity_value3 = PyramidFeatureHistogram<PPFSignature>::comparePyramidFeatureHistograms (pyramid_source, pyramid_target);
00487   EXPECT_NEAR (similarity_value3, 0.87623238563537598, 1e-3);
00488 }
00489 
00490 // Suat G: disabled, since the transformation does not look correct.
00491 // ToDo: update transformation from the ground truth.
00492 #if 0
00493 
00494 TEST (PCL, PPFRegistration)
00495 {
00496   // Transform the source cloud by a large amount
00497   Eigen::Vector3f initial_offset (100, 0, 0);
00498   float angle = M_PI/6;
00499   Eigen::Quaternionf initial_rotation (cos (angle / 2), 0, 0, sin (angle / 2));
00500   PointCloud<PointXYZ> cloud_source_transformed;
00501   transformPointCloud (cloud_source, cloud_source_transformed, initial_offset, initial_rotation);
00502 
00503 
00504   // Create shared pointers
00505   PointCloud<PointXYZ>::Ptr cloud_source_ptr, cloud_target_ptr, cloud_source_transformed_ptr;
00506   cloud_source_transformed_ptr = cloud_source_transformed.makeShared ();
00507   cloud_target_ptr = cloud_target.makeShared ();
00508 
00509   // Estimate normals for both clouds
00510   NormalEstimation<PointXYZ, Normal> normal_estimation;
00511   search::KdTree<PointXYZ>::Ptr search_tree (new search::KdTree<PointXYZ> ());
00512   normal_estimation.setSearchMethod (search_tree);
00513   normal_estimation.setRadiusSearch (0.05);
00514   PointCloud<Normal>::Ptr normals_target (new PointCloud<Normal> ()),
00515       normals_source_transformed (new PointCloud<Normal> ());
00516   normal_estimation.setInputCloud (cloud_target_ptr);
00517   normal_estimation.compute (*normals_target);
00518   normal_estimation.setInputCloud (cloud_source_transformed_ptr);
00519   normal_estimation.compute (*normals_source_transformed);
00520 
00521   PointCloud<PointNormal>::Ptr cloud_target_with_normals (new PointCloud<PointNormal> ()),
00522       cloud_source_transformed_with_normals (new PointCloud<PointNormal> ());
00523   concatenateFields (*cloud_target_ptr, *normals_target, *cloud_target_with_normals);
00524   concatenateFields (*cloud_source_transformed_ptr, *normals_source_transformed, *cloud_source_transformed_with_normals);
00525 
00526   // Compute PPFSignature feature clouds for source cloud
00527   PPFEstimation<PointXYZ, Normal, PPFSignature> ppf_estimator;
00528   PointCloud<PPFSignature>::Ptr features_source_transformed (new PointCloud<PPFSignature> ());
00529   ppf_estimator.setInputCloud (cloud_source_transformed_ptr);
00530   ppf_estimator.setInputNormals (normals_source_transformed);
00531   ppf_estimator.compute (*features_source_transformed);
00532 
00533 
00534   // Train the source cloud - create the hash map search structure
00535   PPFHashMapSearch::Ptr hash_map_search (new PPFHashMapSearch (15.0 / 180 * M_PI,
00536                                                                0.05));
00537   hash_map_search->setInputFeatureCloud (features_source_transformed);
00538 
00539   // Finally, do the registration
00540   PPFRegistration<PointNormal, PointNormal> ppf_registration;
00541   ppf_registration.setSceneReferencePointSamplingRate (20);
00542   ppf_registration.setPositionClusteringThreshold (0.15);
00543   ppf_registration.setRotationClusteringThreshold (45.0 / 180 * M_PI);
00544   ppf_registration.setSearchMethod (hash_map_search);
00545   ppf_registration.setInputCloud (cloud_source_transformed_with_normals);
00546   ppf_registration.setInputTarget (cloud_target_with_normals);
00547 
00548   PointCloud<PointNormal> cloud_output;
00549   ppf_registration.align (cloud_output);
00550   Eigen::Matrix4f transformation = ppf_registration.getFinalTransformation ();
00551 
00552   EXPECT_NEAR (transformation(0, 0), -0.153768, 1e-4);
00553   EXPECT_NEAR (transformation(0, 1), -0.628136, 1e-4);
00554   EXPECT_NEAR (transformation(0, 2), 0.762759, 1e-4);
00555   EXPECT_NEAR (transformation(0, 3), 15.472, 1e-4);
00556   EXPECT_NEAR (transformation(1, 0), 0.967397, 1e-4);
00557   EXPECT_NEAR (transformation(1, 1), -0.252918, 1e-4);
00558   EXPECT_NEAR (transformation(1, 2), -0.0132578, 1e-4);
00559   EXPECT_NEAR (transformation(1, 3), -96.6221, 1e-4);
00560   EXPECT_NEAR (transformation(2, 0), 0.201243, 1e-4);
00561   EXPECT_NEAR (transformation(2, 1), 0.735852, 1e-4);
00562   EXPECT_NEAR (transformation(2, 2), 0.646547, 1e-4);
00563   EXPECT_NEAR (transformation(2, 3), -20.134, 1e-4);
00564   EXPECT_NEAR (transformation(3, 0), 0.000000, 1e-4);
00565   EXPECT_NEAR (transformation(3, 1), 0.000000, 1e-4);
00566   EXPECT_NEAR (transformation(3, 2), 0.000000, 1e-4);
00567   EXPECT_NEAR (transformation(3, 3), 1.000000, 1e-4);
00568 }
00569 #endif
00570 
00571 /* ---[ */
00572 int
00573 main (int argc, char** argv)
00574 {
00575   if (argc < 3)
00576   {
00577     std::cerr << "No test files given. Please download `bun0.pcd` and `bun4.pcd` and pass their path to the test." << std::endl;
00578     return (-1);
00579   }
00580 
00581   // Input
00582   if (loadPCDFile (argv[1], cloud_source) < 0)
00583   {
00584     std::cerr << "Failed to read test file. Please download `bun0.pcd` and pass its path to the test." << std::endl;
00585     return (-1);
00586   }
00587   if (loadPCDFile (argv[2], cloud_target) < 0)
00588   {
00589     std::cerr << "Failed to read test file. Please download `bun4.pcd` and pass its path to the test." << std::endl;
00590     return (-1);
00591   }
00592 
00593   testing::InitGoogleTest (&argc, argv);
00594   return (RUN_ALL_TESTS ());
00595 
00596   // Tranpose the cloud_model
00597   /*for (size_t i = 0; i < cloud_model.points.size (); ++i)
00598   {
00599   //  cloud_model.points[i].z += 1;
00600   }*/
00601 }
00602 /* ]--- */


pcl
Author(s): Open Perception
autogenerated on Mon Oct 6 2014 03:18:28