test_correspondence_rejectors.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-2012, 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 #include <pcl/point_types.h>
00042 #include <pcl/point_cloud.h>
00043 #include <pcl/common/eigen.h>
00044 #include <pcl/common/transforms.h>
00045 #include <pcl/io/pcd_io.h>
00046 #include <pcl/registration/correspondence_rejection_median_distance.h>
00047 #include <pcl/registration/correspondence_rejection_poly.h>
00048 
00049 #include <boost/random.hpp>
00050 
00051 pcl::PointCloud<pcl::PointXYZ> cloud;
00052 
00054 TEST (CorrespondenceRejectors, CorrespondenceRejectionMedianDistance)
00055 {
00056   pcl::CorrespondencesPtr corresps (new pcl::Correspondences ());
00057   for (int i = 0; i <= 10; ++i)
00058   {
00059     pcl::Correspondence c;
00060     c.distance = static_cast<float> (i * i);
00061     corresps->push_back (c);
00062   }
00063 
00064   pcl::registration::CorrespondenceRejectorMedianDistance rejector;
00065   rejector.setInputCorrespondences (corresps);
00066   rejector.setMedianFactor (2.0);
00067 
00068   pcl::Correspondences corresps_filtered;
00069   rejector.getCorrespondences (corresps_filtered);
00070 
00071   EXPECT_EQ (corresps_filtered.size (), 8);
00072   for (int i = 0; i < 8; ++i)
00073     EXPECT_NEAR (corresps_filtered[i].distance, static_cast<float> (i * i), 1e-5);
00074 }
00075 
00077 TEST (CorrespondenceRejectors, CorrespondenceRejectionPoly)
00078 {
00079   // Size of point cloud
00080   const int size = static_cast<int> (cloud.size ());
00081   
00082   // Ground truth correspondences
00083   pcl::Correspondences corr (size);
00084   for (int i = 0; i < size; ++i)
00085     corr[i].index_query = corr[i].index_match = i;
00086   
00087   // Scramble the first floor(size*3/4) correspondences by adding floor(size/8) to the match index
00088   const int last = 3*size/4;
00089   const int inc = size/8;
00090   for (int i = 0; i < last; ++i)
00091     corr[i].index_match += inc;  
00092   
00093   // Transform the target
00094   pcl::PointCloud<pcl::PointXYZ> target;
00095   Eigen::Vector3f t(0.1f, 0.2f, 0.3f);
00096   Eigen::Quaternionf q (float (std::cos (0.5*M_PI_4)), 0.0f, 0.0f, float (std::sin (0.5*M_PI_4)));
00097   pcl::transformPointCloud (cloud, target, t, q);
00098   
00099   // Noisify the target with a known seed and N(0, 0.005) using deterministic sampling
00100   boost::mt19937 rng;
00101   rng.seed (1e6);
00102   boost::normal_distribution<> nd (0, 0.005);
00103   boost::variate_generator<boost::mt19937&, boost::normal_distribution<> > var_nor (rng, nd);
00104   for (pcl::PointCloud<pcl::PointXYZ>::iterator it = target.begin (); it != target.end (); ++it)
00105   {
00106     it->x += static_cast<float> (var_nor ());
00107     it->y += static_cast<float> (var_nor ());
00108     it->z += static_cast<float> (var_nor ());
00109   }
00110   
00111   // Ensure deterministic sampling inside the rejector
00112   std::srand (1e6);
00113   
00114   // Create a rejection object
00115   pcl::registration::CorrespondenceRejectorPoly<pcl::PointXYZ, pcl::PointXYZ> reject;
00116   reject.setIterations (10000);
00117   reject.setCardinality (3);
00118   reject.setSimilarityThreshold (0.75f);
00119   reject.setInputSource (cloud.makeShared ());
00120   reject.setInputTarget (target.makeShared ());
00121   
00122   // Run rejection
00123   pcl::Correspondences result;
00124   reject.getRemainingCorrespondences (corr, result);
00125   
00126   // Ground truth fraction of inliers and estimated fraction of inliers
00127   const float ground_truth_frac = float (size-last) / float (size);
00128   const float accepted_frac = float (result.size()) / float (size);
00129 
00130   /*
00131    * Test criterion 1: verify that the method accepts at least 25 % of the input correspondences,
00132    * but not too many
00133    */
00134   EXPECT_GE(accepted_frac, ground_truth_frac);
00135   EXPECT_LE(accepted_frac, 1.5f*ground_truth_frac);
00136   
00137   /*
00138    * Test criterion 2: expect high precision/recall. The true positives are the unscrambled correspondences
00139    * where the query/match index are equal.
00140    */
00141   unsigned int true_positives = 0;
00142   for (unsigned int i = 0; i < result.size(); ++i)
00143     if (result[i].index_query == result[i].index_match)
00144       ++true_positives;
00145   const unsigned int false_positives = static_cast<unsigned int> (result.size()) - true_positives;
00146 
00147   const double precision = double(true_positives) / double(true_positives+false_positives);
00148   const double recall = double(true_positives) / double(size-last);
00149   EXPECT_NEAR(precision, 1.0, 0.4);
00150   EXPECT_NEAR(recall, 1.0, 0.2);
00151 }
00152 
00153 
00154 /* ---[ */
00155 int
00156   main (int argc, char** argv)
00157 {
00158   if (argc < 2)
00159   {
00160     std::cerr << "No test files given. Please download `bunny.pcd` and pass its path to the test." << std::endl;
00161     return (-1);
00162   }
00163 
00164   // Input
00165   if (pcl::io::loadPCDFile (argv[1], cloud) < 0)
00166   {
00167     std::cerr << "Failed to read test file. Please download `bunny.pcd` and pass its path to the test." << std::endl;
00168     return (-1);
00169   }
00170   
00171   testing::InitGoogleTest (&argc, argv);
00172   return (RUN_ALL_TESTS ());
00173 }
00174 /* ]--- */


pcl
Author(s): Open Perception
autogenerated on Wed Aug 26 2015 15:34:40