test_shot_estimation.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 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$
00037  *
00038  */
00039 
00040 #include <gtest/gtest.h>
00041 #include <pcl/point_cloud.h>
00042 #include <pcl/features/normal_3d_omp.h>
00043 #include <pcl/io/pcd_io.h>
00044 #include <pcl/features/shot.h>
00045 #include <pcl/features/shot_omp.h>
00046 #include <pcl/features/3dsc.h>
00047 #include <pcl/features/usc.h>
00048 
00049 using namespace pcl;
00050 using namespace pcl::io;
00051 using namespace std;
00052 
00053 typedef search::KdTree<PointXYZ>::Ptr KdTreePtr;
00054 
00055 PointCloud<PointXYZ> cloud;
00056 vector<int> indices;
00057 KdTreePtr tree;
00058 
00060 void
00061 shotCopyPointCloud (const PointCloud<SHOT> &cloud_in, const std::vector<int> &indices,
00062                     PointCloud<SHOT> &cloud_out)
00063 {
00064   // Allocate enough space and copy the basics
00065   cloud_out.points.resize (indices.size ());
00066   cloud_out.header   = cloud_in.header;
00067   cloud_out.width    = static_cast<uint32_t> (indices.size ());
00068   cloud_out.height   = 1;
00069   if (cloud_in.is_dense)
00070     cloud_out.is_dense = true;
00071   else
00072     // It's not necessarily true that is_dense is false if cloud_in.is_dense is false
00073     // To verify this, we would need to iterate over all points and check for NaNs
00074     cloud_out.is_dense = false;
00075 
00076   // Iterate over each point
00077   for (size_t i = 0; i < indices.size (); ++i)
00078   {
00079     std::copy (cloud_in.points[indices[i]].descriptor.begin (),
00080                cloud_in.points[indices[i]].descriptor.end (),
00081                std::back_inserter(cloud_out.points[i].descriptor));
00082     memcpy (cloud_out.points[i].rf, cloud_in.points[indices[i]].rf, sizeof (float) * 9);
00083   }
00084 }
00085 
00087 template <typename FeatureEstimation, typename PointT, typename NormalT, typename OutputT> FeatureEstimation
00088 createSHOTDesc (const typename PointCloud<NormalT>::Ptr & normals,
00089                 const int nr_shape_bins = 10,
00090                 const int = 30,
00091                 const bool = true,
00092                 const bool = false)
00093 {
00094   FeatureEstimation f (nr_shape_bins);
00095   f.setInputNormals (normals);
00096   return (f);
00097 }
00098 
00100 template <typename FeatureEstimation, typename NormalT, typename OutputT> FeatureEstimation
00101 createSHOTDesc (const typename PointCloud<NormalT>::Ptr & normals,
00102                 const int nr_shape_bins = 10,
00103                 const int nr_color_bins = 30,
00104                 const bool describe_shape = true,
00105                 const bool describe_color = false)
00106 {
00107   FeatureEstimation f (describe_shape, describe_color, nr_shape_bins,nr_color_bins);
00108   f.setInputNormals (normals);
00109   return (f);
00110 }
00111 
00113 template <> ShapeContext3DEstimation<PointXYZ, Normal, SHOT>
00114 createSHOTDesc<ShapeContext3DEstimation<PointXYZ, Normal, SHOT>, PointXYZ, Normal, SHOT> (
00115     const PointCloud<Normal>::Ptr & normals,
00116     const int,
00117     const int,
00118     const bool, 
00119     const bool)
00120 {
00121   ShapeContext3DEstimation<PointXYZ, Normal, SHOT> sc3d;
00122   sc3d.setAzimuthBins (4);
00123   sc3d.setElevationBins (4);
00124   sc3d.setRadiusBins (4);
00125   sc3d.setMinimalRadius (0.004);
00126   sc3d.setPointDensityRadius (0.008);
00127   sc3d.setInputNormals (normals);
00128   return (sc3d);
00129 }
00130 
00132 template <> UniqueShapeContext<PointXYZ, SHOT>
00133 createSHOTDesc<UniqueShapeContext<PointXYZ, SHOT>, PointXYZ, Normal, SHOT> (
00134     const PointCloud<Normal>::Ptr &,
00135     const int,
00136     const int,
00137     const bool,
00138     const bool)
00139 {
00140   UniqueShapeContext<PointXYZ, SHOT> usc;
00141   usc.setAzimuthBins (4);
00142   usc.setElevationBins (4);
00143   usc.setRadiusBins (4);
00144   usc.setMinimalRadius (0.004);
00145   usc.setPointDensityRadius (0.008);
00146   usc.setLocalRadius (0.04f);
00147   return (usc);
00148 }
00149 
00151 template <typename FeatureEstimation, typename PointT, typename NormalT, typename OutputT> void
00152 testSHOTIndicesAndSearchSurface (const typename PointCloud<PointT>::Ptr & points,
00153                                  const typename PointCloud<NormalT>::Ptr & normals,
00154                                  const boost::shared_ptr<vector<int> > & indices,
00155                                  const int nr_shape_bins = 10,
00156                                  const int nr_color_bins = 30,
00157                                  const bool describe_shape = true,
00158                                  const bool describe_color = false)
00159 {
00160   double radius = 0.04;
00161   //
00162   // Test setIndices and setSearchSurface
00163   //
00164   PointCloud<OutputT> full_output, output0, output1, output2;
00165 
00166   // Compute for all points and then subsample the results
00167   FeatureEstimation est0 = createSHOTDesc<FeatureEstimation, PointT, NormalT, OutputT>(normals, nr_shape_bins,nr_color_bins,describe_shape,describe_color);
00168   est0.setSearchMethod (typename search::KdTree<PointT>::Ptr (new search::KdTree<PointT>));
00169   est0.setRadiusSearch (radius);
00170   est0.setInputCloud (points);
00171   est0.compute (full_output);
00172 
00173   shotCopyPointCloud (full_output, *indices, output0);
00174 
00175   // Compute with all points as "search surface" and the specified sub-cloud as "input"
00176   typename PointCloud<PointT>::Ptr subpoints (new PointCloud<PointT>);
00177   copyPointCloud (*points, *indices, *subpoints);
00178   FeatureEstimation est1 = createSHOTDesc<FeatureEstimation, PointT, NormalT, OutputT>(normals, nr_shape_bins,nr_color_bins,describe_shape,describe_color);
00179   est1.setSearchMethod (typename search::KdTree<PointT>::Ptr (new search::KdTree<PointT>));
00180   est1.setRadiusSearch (radius);
00181   est1.setInputCloud (subpoints);
00182   est1.setSearchSurface (points);
00183   est1.compute (output1);
00184 
00186   FeatureEstimation est2 = createSHOTDesc<FeatureEstimation, PointT, NormalT, OutputT>(normals, nr_shape_bins,nr_color_bins,describe_shape,describe_color);
00187   est2.setSearchMethod (typename search::KdTree<PointT>::Ptr (new search::KdTree<PointT>));
00188   est2.setRadiusSearch (radius);
00189   est2.setInputCloud (points);
00190   est2.setIndices (indices);
00191   est2.compute (output2);
00192 
00193   // All three of the above cases should produce equivalent results
00194   ASSERT_EQ (output0.size (), output1.size ());
00195   ASSERT_EQ (output1.size (), output2.size ());
00196   for (size_t i = 0; i < output1.size (); ++i)
00197   {
00198     for (size_t j = 0; j < output0.points[i].descriptor.size(); ++j)
00199     {
00200       ASSERT_EQ (output0.points[i].descriptor[j], output1.points[i].descriptor[j]);
00201       ASSERT_EQ (output1.points[i].descriptor[j], output2.points[i].descriptor[j]);
00202     }
00203   }
00204 
00205   //
00206   // Test the combination of setIndices and setSearchSurface
00207   //
00208   PointCloud<OutputT> output3, output4;
00209 
00210   boost::shared_ptr<vector<int> > indices2 (new vector<int> (0));
00211   for (size_t i = 0; i < (indices->size ()/2); ++i)
00212     indices2->push_back (static_cast<int> (i));
00213 
00214   // Compute with all points as search surface + the specified sub-cloud as "input" but for only a subset of indices
00215   FeatureEstimation est3 = createSHOTDesc<FeatureEstimation, PointT, NormalT, OutputT>(normals, nr_shape_bins,nr_color_bins,describe_shape,describe_color);
00216   est3.setSearchMethod (typename search::KdTree<PointT>::Ptr (new search::KdTree<PointT>));
00217   est3.setRadiusSearch (0.04);
00218   est3.setSearchSurface (points);
00219   est3.setInputCloud (subpoints);
00220   est3.setIndices (indices2);
00221   est3.compute (output3);
00222 
00223   // Start with features for each point in "subpoints" and then subsample the results
00224   shotCopyPointCloud (output0, *indices2, output4); // (Re-using "output0" from above)
00225 
00226   // The two cases above should produce equivalent results
00227   ASSERT_EQ (output3.size (), output4.size ());
00228   for (size_t i = 0; i < output3.size (); ++i)
00229     for (size_t j = 0; j < output3.points[i].descriptor.size (); ++j)
00230       ASSERT_EQ (output3.points[i].descriptor[j], output4.points[i].descriptor[j]);
00231 }
00232 
00234 TEST (PCL, SHOTShapeEstimation)
00235 {
00236   // Estimate normals first
00237   double mr = 0.002;
00238   NormalEstimation<PointXYZ, Normal> n;
00239   PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
00240   // set parameters
00241   n.setInputCloud (cloud.makeShared ());
00242   boost::shared_ptr<vector<int> > indicesptr (new vector<int> (indices));
00243   n.setIndices (indicesptr);
00244   n.setSearchMethod (tree);
00245   n.setRadiusSearch (20 * mr);
00246   n.compute (*normals);
00247 
00248   EXPECT_NEAR (normals->points[103].normal_x, 0.36683175, 1e-4);
00249   EXPECT_NEAR (normals->points[103].normal_y, -0.44696972, 1e-4);
00250   EXPECT_NEAR (normals->points[103].normal_z, -0.81587529, 1e-4);
00251   EXPECT_NEAR (normals->points[200].normal_x, -0.71414840, 1e-4);
00252   EXPECT_NEAR (normals->points[200].normal_y, -0.06002361, 1e-4);
00253   EXPECT_NEAR (normals->points[200].normal_z, -0.69741613, 1e-4);
00254 
00255   EXPECT_NEAR (normals->points[140].normal_x, -0.45109111, 1e-4);
00256   EXPECT_NEAR (normals->points[140].normal_y, -0.19499126, 1e-4);
00257   EXPECT_NEAR (normals->points[140].normal_z, -0.87091631, 1e-4);
00258 
00259   SHOTEstimation<PointXYZ, Normal, SHOT> shot;
00260   shot.setInputNormals (normals);
00261   EXPECT_EQ (shot.getInputNormals (), normals);
00262   shot.setRadiusSearch (20 * mr);
00263 
00264   // Object
00265   PointCloud<SHOT>::Ptr shots (new PointCloud<SHOT> ());
00266 
00267   // set parameters
00268   shot.setInputCloud (cloud.makeShared ());
00269   shot.setIndices (indicesptr);
00270   shot.setSearchMethod (tree);
00271 
00272   // estimate
00273   shot.compute (*shots);
00274   EXPECT_EQ (shots->points.size (), indices.size ());
00275 
00276   EXPECT_NEAR (shots->points[103].descriptor[9 ], 0.0072018504, 1e-4);
00277   EXPECT_NEAR (shots->points[103].descriptor[10], 0.0023103887, 1e-4);
00278   EXPECT_NEAR (shots->points[103].descriptor[11], 0.0024724449, 1e-4);
00279   EXPECT_NEAR (shots->points[103].descriptor[19], 0.0031367359, 1e-4);
00280   EXPECT_NEAR (shots->points[103].descriptor[20], 0.17439659, 1e-4);
00281   EXPECT_NEAR (shots->points[103].descriptor[21], 0.070665278, 1e-4);
00282   EXPECT_NEAR (shots->points[103].descriptor[42], 0.013304681, 1e-4);
00283   EXPECT_NEAR (shots->points[103].descriptor[53], 0.0073520984, 1e-4);
00284   EXPECT_NEAR (shots->points[103].descriptor[54], 0.013584172, 1e-4);
00285   EXPECT_NEAR (shots->points[103].descriptor[55], 0.0050609680, 1e-4);
00286 
00287 
00288   // Test results when setIndices and/or setSearchSurface are used
00289 
00290   boost::shared_ptr<vector<int> > test_indices (new vector<int> (0));
00291   for (size_t i = 0; i < cloud.size (); i+=3)
00292     test_indices->push_back (static_cast<int> (i));
00293 
00294   testSHOTIndicesAndSearchSurface<SHOTEstimation<PointXYZ, Normal, SHOT>, PointXYZ, Normal, SHOT> (cloud.makeShared (), normals, test_indices);
00295 }
00296 
00298 TEST (PCL, GenericSHOTShapeEstimation)
00299 {
00300   // SHOT length
00301   const int shapeStep_ = 20;
00302   //const int dim = 32*(shapeStep_+1);
00303 
00304   // Estimate normals first
00305   double mr = 0.002;
00306   NormalEstimation<PointXYZ, Normal> n;
00307   PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
00308   // set parameters
00309   n.setInputCloud (cloud.makeShared ());
00310   boost::shared_ptr<vector<int> > indicesptr (new vector<int> (indices));
00311   n.setIndices (indicesptr);
00312   n.setSearchMethod (tree);
00313   n.setRadiusSearch (20 * mr);
00314   n.compute (*normals);
00315 
00316   SHOTEstimation<PointXYZ, Normal, SHOT> shot (shapeStep_);
00317   shot.setInputNormals (normals);
00318   EXPECT_EQ (shot.getInputNormals (), normals);
00319 
00320   shot.setRadiusSearch (20 * mr);
00321 
00322   PointCloud< SHOT >::Ptr shots (new PointCloud< SHOT > ());
00323 
00324   // set parameters
00325   shot.setInputCloud (cloud.makeShared ());
00326   shot.setIndices (indicesptr);
00327   shot.setSearchMethod (tree);
00328 
00329   // estimate
00330   shot.compute (*shots);
00331   EXPECT_EQ (shots->points.size (), indices.size ());
00332 
00333   EXPECT_NEAR (shots->points[103].descriptor[18], 0.0077019366, 1e-5);
00334   EXPECT_NEAR (shots->points[103].descriptor[19], 0.0024708188, 1e-5);
00335   EXPECT_NEAR (shots->points[103].descriptor[21], 0.0079652183, 1e-5);
00336   EXPECT_NEAR (shots->points[103].descriptor[38], 0.0067090928, 1e-5);
00337   EXPECT_NEAR (shots->points[103].descriptor[39], 0.17498907, 1e-5);
00338   EXPECT_NEAR (shots->points[103].descriptor[40], 0.078413926, 1e-5);
00339   EXPECT_NEAR (shots->points[103].descriptor[81], 0.014228539, 1e-5);
00340   EXPECT_NEAR (shots->points[103].descriptor[103], 0.022390056, 1e-5);
00341   EXPECT_NEAR (shots->points[103].descriptor[105], 0.0058866320, 1e-5);
00342   EXPECT_NEAR (shots->points[103].descriptor[123], 0.019105887, 1e-5);
00343 
00344   // Test results when setIndices and/or setSearchSurface are used
00345   boost::shared_ptr<vector<int> > test_indices (new vector<int> (0));
00346   for (size_t i = 0; i < cloud.size (); i+=3)
00347     test_indices->push_back (static_cast<int> (i));
00348 
00349   testSHOTIndicesAndSearchSurface<SHOTEstimation<PointXYZ, Normal, SHOT>, PointXYZ, Normal, SHOT> (cloud.makeShared (), normals, test_indices, shapeStep_);
00350 }
00351 
00353 TEST (PCL, SHOTShapeAndColorEstimation)
00354 {
00355   double mr = 0.002;
00356   // Estimate normals first
00357   NormalEstimation<PointXYZ, Normal> n;
00358   PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
00359   // set parameters
00360   n.setInputCloud (cloud.makeShared ());
00361   boost::shared_ptr<vector<int> > indicesptr (new vector<int> (indices));
00362   n.setIndices (indicesptr);
00363   n.setSearchMethod (tree);
00364   n.setRadiusSearch (20 * mr);
00365   n.compute (*normals);
00366 
00367   search::KdTree<PointXYZRGBA>::Ptr rgbaTree;
00368   rgbaTree.reset (new search::KdTree<PointXYZRGBA> (false));
00369 
00370   // Object
00371   SHOTEstimation<PointXYZRGBA, Normal, SHOT> shot (true, true);
00372   shot.setInputNormals (normals);
00373   EXPECT_EQ (shot.getInputNormals (), normals);
00374 
00375   shot.setRadiusSearch ( 20 * mr);
00376 
00377   // Create fake point cloud with colors
00378   PointCloud<PointXYZRGBA> cloudWithColors;
00379   for (int i = 0; i < static_cast<int> (cloud.points.size ()); ++i)
00380   {
00381     PointXYZRGBA p;
00382     p.x = cloud.points[i].x;
00383     p.y = cloud.points[i].y;
00384     p.z = cloud.points[i].z;
00385 
00386     p.rgba = ( (i%255) << 16 ) + ( ( (255 - i ) %255) << 8) + ( ( i*37 ) %255);
00387     cloudWithColors.push_back(p);
00388   }
00389 
00390   rgbaTree->setInputCloud (cloudWithColors.makeShared ());
00391   PointCloud<SHOT>::Ptr shots (new PointCloud<SHOT>);
00392 
00393   shot.setInputCloud (cloudWithColors.makeShared ());
00394   shot.setIndices (indicesptr);
00395   shot.setSearchMethod (rgbaTree);
00396 
00397   // estimate
00398   shot.compute (*shots);
00399   EXPECT_EQ (shots->points.size (), indices.size ());
00400 
00401   EXPECT_NEAR (shots->points[103].descriptor[10], 0.0020453099, 1e-5);
00402   EXPECT_NEAR (shots->points[103].descriptor[11], 0.0021887729, 1e-5);
00403   EXPECT_NEAR (shots->points[103].descriptor[21], 0.062557608, 1e-5);
00404   EXPECT_NEAR (shots->points[103].descriptor[42], 0.011778189, 1e-5);
00405   EXPECT_NEAR (shots->points[103].descriptor[53], 0.0065085669, 1e-5);
00406   EXPECT_NEAR (shots->points[103].descriptor[54], 0.012025614, 1e-5);
00407   EXPECT_NEAR (shots->points[103].descriptor[55], 0.0044803056, 1e-5);
00408   EXPECT_NEAR (shots->points[103].descriptor[64], 0.064429596, 1e-5);
00409   EXPECT_NEAR (shots->points[103].descriptor[65], 0.046486385, 1e-5);
00410   EXPECT_NEAR (shots->points[103].descriptor[86], 0.011518310, 1e-5);
00411 
00412   EXPECT_NEAR (shots->points[103].descriptor[357], 0.0020453099, 1e-5);
00413   EXPECT_NEAR (shots->points[103].descriptor[360], 0.0027993850, 1e-5);
00414   EXPECT_NEAR (shots->points[103].descriptor[386], 0.045115642, 1e-5);
00415   EXPECT_NEAR (shots->points[103].descriptor[387], 0.059068538, 1e-5);
00416   EXPECT_NEAR (shots->points[103].descriptor[389], 0.0047547864, 1e-5);
00417   EXPECT_NEAR (shots->points[103].descriptor[453], 0.0051176427, 1e-5);
00418   EXPECT_NEAR (shots->points[103].descriptor[481], 0.0053625242, 1e-5);
00419   EXPECT_NEAR (shots->points[103].descriptor[482], 0.012025614, 1e-5);
00420   EXPECT_NEAR (shots->points[103].descriptor[511], 0.0057367259, 1e-5);
00421   EXPECT_NEAR (shots->points[103].descriptor[512], 0.048357654, 1e-5);
00422 
00423   // Test results when setIndices and/or setSearchSurface are used
00424   boost::shared_ptr<vector<int> > test_indices (new vector<int> (0));
00425   for (size_t i = 0; i < cloud.size (); i+=3)
00426     test_indices->push_back (static_cast<int> (i));
00427 
00428   testSHOTIndicesAndSearchSurface<SHOTEstimation<PointXYZRGBA, Normal, SHOT>, PointXYZRGBA, Normal, SHOT> (cloudWithColors.makeShared (), normals, test_indices);
00429 }
00430 
00432 TEST (PCL, SHOTShapeEstimationOpenMP)
00433 {
00434   // Estimate normals first
00435   double mr = 0.002;
00436   NormalEstimationOMP<PointXYZ, Normal> n (omp_get_max_threads ());
00437   PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
00438   // set parameters
00439   n.setInputCloud (cloud.makeShared ());
00440   boost::shared_ptr<vector<int> > indicesptr (new vector<int> (indices));
00441   n.setIndices (indicesptr);
00442   n.setSearchMethod (tree);
00443   n.setRadiusSearch (20 * mr);
00444   n.compute (*normals);
00445 
00446   SHOTEstimationOMP<PointXYZ, Normal, SHOT> shot;
00447   shot.setInputNormals (normals);
00448   EXPECT_EQ (shot.getInputNormals (), normals);
00449 
00450   shot.setRadiusSearch ( 20 * mr);
00451 
00452   // Object
00453   PointCloud<SHOT>::Ptr shots (new PointCloud<SHOT>);
00454 
00455   // set parameters
00456   shot.setInputCloud (cloud.makeShared ());
00457   shot.setIndices (indicesptr);
00458   shot.setSearchMethod (tree);
00459 
00460   // estimate
00461   shot.compute (*shots);
00462   EXPECT_EQ (shots->points.size (), indices.size ());
00463 
00464   EXPECT_NEAR (shots->points[103].descriptor[9 ], 0.0072018504, 1e-4);
00465   EXPECT_NEAR (shots->points[103].descriptor[10], 0.0023103887, 1e-4);
00466   EXPECT_NEAR (shots->points[103].descriptor[11], 0.0024724449, 1e-4);
00467   EXPECT_NEAR (shots->points[103].descriptor[19], 0.0031367359, 1e-4);
00468   EXPECT_NEAR (shots->points[103].descriptor[20], 0.17439659, 1e-4);
00469   EXPECT_NEAR (shots->points[103].descriptor[21], 0.070665278, 1e-4);
00470   EXPECT_NEAR (shots->points[103].descriptor[42], 0.013304681, 1e-4);
00471   EXPECT_NEAR (shots->points[103].descriptor[53], 0.0073520984, 1e-4);
00472   EXPECT_NEAR (shots->points[103].descriptor[54], 0.013584172, 1e-4);
00473   EXPECT_NEAR (shots->points[103].descriptor[55], 0.0050609680, 1e-4);
00474 
00475   // Test results when setIndices and/or setSearchSurface are used
00476   boost::shared_ptr<vector<int> > test_indices (new vector<int> (0));
00477   for (size_t i = 0; i < cloud.size (); i+=3)
00478     test_indices->push_back (static_cast<int> (i));
00479 
00480   testSHOTIndicesAndSearchSurface<SHOTEstimationOMP<PointXYZ, Normal, SHOT>, PointXYZ, Normal, SHOT> (cloud.makeShared (), normals, test_indices);
00481 }
00482 
00484 TEST (PCL,SHOTShapeAndColorEstimationOpenMP)
00485 {
00486   double mr = 0.002;
00487   // Estimate normals first
00488   NormalEstimation<PointXYZ, Normal> n;
00489   PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
00490   // set parameters
00491   n.setInputCloud (cloud.makeShared ());
00492   boost::shared_ptr<vector<int> > indicesptr (new vector<int> (indices));
00493   n.setIndices (indicesptr);
00494   n.setSearchMethod (tree);
00495   n.setRadiusSearch (20 * mr);
00496   n.compute (*normals);
00497 
00498   search::KdTree<PointXYZRGBA>::Ptr rgbaTree;
00499 
00500   rgbaTree.reset (new search::KdTree<PointXYZRGBA> (false));
00501 
00502   // Object
00503   SHOTEstimationOMP<PointXYZRGBA, Normal, SHOT> shot (true, true, -1);
00504   shot.setInputNormals (normals);
00505 
00506   EXPECT_EQ (shot.getInputNormals (), normals);
00507 
00508   shot.setRadiusSearch ( 20 * mr);
00509 
00510   // Create fake point cloud with colors
00511   PointCloud<PointXYZRGBA> cloudWithColors;
00512   for (int i = 0; i < static_cast<int> (cloud.points.size ()); ++i)
00513   {
00514     PointXYZRGBA p;
00515     p.x = cloud.points[i].x;
00516     p.y = cloud.points[i].y;
00517     p.z = cloud.points[i].z;
00518 
00519     p.rgba = ( (i%255) << 16 ) + ( ( (255 - i ) %255) << 8) + ( ( i*37 ) %255);
00520     cloudWithColors.push_back(p);
00521   }
00522 
00523   rgbaTree->setInputCloud (cloudWithColors.makeShared ());
00524 
00525   PointCloud<SHOT>::Ptr shots (new PointCloud<SHOT> ());
00526 
00527   shot.setInputCloud (cloudWithColors.makeShared ());
00528   shot.setIndices (indicesptr);
00529   shot.setSearchMethod (rgbaTree);
00530 
00531   // estimate
00532   shot.compute (*shots);
00533   EXPECT_EQ (shots->points.size (), indices.size ());
00534 
00535   EXPECT_NEAR (shots->points[103].descriptor[10], 0.0020453099, 1e-5);
00536   EXPECT_NEAR (shots->points[103].descriptor[11], 0.0021887729, 1e-5);
00537   EXPECT_NEAR (shots->points[103].descriptor[21], 0.062557608, 1e-5);
00538   EXPECT_NEAR (shots->points[103].descriptor[42], 0.011778189, 1e-5);
00539   EXPECT_NEAR (shots->points[103].descriptor[53], 0.0065085669, 1e-5);
00540   EXPECT_NEAR (shots->points[103].descriptor[54], 0.012025614, 1e-5);
00541   EXPECT_NEAR (shots->points[103].descriptor[55], 0.0044803056, 1e-5);
00542   EXPECT_NEAR (shots->points[103].descriptor[64], 0.064429596, 1e-5);
00543   EXPECT_NEAR (shots->points[103].descriptor[65], 0.046486385, 1e-5);
00544   EXPECT_NEAR (shots->points[103].descriptor[86], 0.011518310, 1e-5);
00545 
00546   EXPECT_NEAR (shots->points[103].descriptor[357], 0.0020453099, 1e-5);
00547   EXPECT_NEAR (shots->points[103].descriptor[360], 0.0027993850, 1e-5);
00548   EXPECT_NEAR (shots->points[103].descriptor[386], 0.045115642, 1e-5);
00549   EXPECT_NEAR (shots->points[103].descriptor[387], 0.059068538, 1e-5);
00550   EXPECT_NEAR (shots->points[103].descriptor[389], 0.0047547864, 1e-5);
00551   EXPECT_NEAR (shots->points[103].descriptor[453], 0.0051176427, 1e-5);
00552   EXPECT_NEAR (shots->points[103].descriptor[481], 0.0053625242, 1e-5);
00553   EXPECT_NEAR (shots->points[103].descriptor[482], 0.012025614, 1e-5);
00554   EXPECT_NEAR (shots->points[103].descriptor[511], 0.0057367259, 1e-5);
00555   EXPECT_NEAR (shots->points[103].descriptor[512], 0.048357654, 1e-5);
00556 
00557   // Test results when setIndices and/or setSearchSurface are used
00558   boost::shared_ptr<vector<int> > test_indices (new vector<int> (0));
00559   for (size_t i = 0; i < cloud.size (); i+=3)
00560     test_indices->push_back (static_cast<int> (i));
00561 
00562   testSHOTIndicesAndSearchSurface<SHOTEstimationOMP<PointXYZRGBA, Normal, SHOT>, PointXYZRGBA, Normal, SHOT> (cloudWithColors.makeShared (), normals, test_indices);
00563 }
00564 
00566 TEST (PCL, 3DSCEstimation)
00567 {
00568   float meshRes = 0.002f;
00569   size_t nBinsL = 4;
00570   size_t nBinsK = 4;
00571   size_t nBinsJ = 4;
00572   float radius = 20.0f * meshRes;
00573   float rmin = radius / 10.0f;
00574   float ptDensityRad = radius / 5.0f;
00575 
00576   PointCloud<PointXYZ>::Ptr cloudptr = cloud.makeShared ();
00577 
00578   // Estimate normals first
00579   NormalEstimation<PointXYZ, Normal> ne;
00580   PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
00581   // set parameters
00582   ne.setInputCloud (cloudptr);
00583   ne.setSearchMethod (tree);
00584   ne.setRadiusSearch (radius);
00585   // estimate
00586   ne.compute (*normals);
00587   ShapeContext3DEstimation<PointXYZ, Normal, SHOT> sc3d;
00588   sc3d.setInputCloud (cloudptr);
00589   sc3d.setInputNormals (normals);
00590   sc3d.setSearchMethod (tree);
00591   sc3d.setRadiusSearch (radius);
00592   sc3d.setAzimuthBins (nBinsL);
00593   sc3d.setElevationBins (nBinsK);
00594   sc3d.setRadiusBins (nBinsJ);
00595   sc3d.setMinimalRadius (rmin);
00596   sc3d.setPointDensityRadius (ptDensityRad);
00597   // Compute the features
00598   PointCloud<SHOT>::Ptr sc3ds (new PointCloud<SHOT> ());
00599   sc3d.compute (*sc3ds);
00600   EXPECT_EQ (sc3ds->size (), cloud.size ());
00601 
00602   // 3DSC does not define a repeatable local RF, we set it to zero to signal it to the user
00603   //EXPECT_NEAR ((*sc3ds)[0].rf[0], 0.2902f, 1e-4f);
00604   //EXPECT_NEAR ((*sc3ds)[0].rf[1], 0.7334f, 1e-4f);
00605   //EXPECT_NEAR ((*sc3ds)[0].rf[2], -0.6146f, 1e-4f);
00606   //EXPECT_NEAR ((*sc3ds)[0].rf[3], 0.9486f, 1e-4f);
00607   //EXPECT_NEAR ((*sc3ds)[0].rf[4], -0.3051f, 1e-4f);
00608   //EXPECT_NEAR ((*sc3ds)[0].rf[5], 0.0838f, 1e-4f);
00609   //EXPECT_NEAR ((*sc3ds)[0].rf[6], -0.1261f, 1e-4f);
00610   //EXPECT_NEAR ((*sc3ds)[0].rf[7], -0.6074f, 1e-4f);
00611   //EXPECT_NEAR ((*sc3ds)[0].rf[8], -0.7843f, 1e-4f);
00612 
00613   EXPECT_NEAR ((*sc3ds)[0].rf[0], 0.0f, 1e-4f);
00614   EXPECT_NEAR ((*sc3ds)[0].rf[1], 0.0f, 1e-4f);
00615   EXPECT_NEAR ((*sc3ds)[0].rf[2], 0.0f, 1e-4f);
00616   EXPECT_NEAR ((*sc3ds)[0].rf[3], 0.0f, 1e-4f);
00617   EXPECT_NEAR ((*sc3ds)[0].rf[4], 0.0f, 1e-4f);
00618   EXPECT_NEAR ((*sc3ds)[0].rf[5], 0.0f, 1e-4f);
00619   EXPECT_NEAR ((*sc3ds)[0].rf[6], 0.0f, 1e-4f);
00620   EXPECT_NEAR ((*sc3ds)[0].rf[7], 0.0f, 1e-4f);
00621   EXPECT_NEAR ((*sc3ds)[0].rf[8], 0.0f, 1e-4f);
00622 
00623   EXPECT_EQ ((*sc3ds)[0].descriptor.size (), 64);
00624   EXPECT_NEAR ((*sc3ds)[0].descriptor[4], 52.2474f, 1e-4f);
00625   EXPECT_NEAR ((*sc3ds)[0].descriptor[6], 150.901611328125, 1e-4f);
00626   EXPECT_NEAR ((*sc3ds)[0].descriptor[7], 169.09703063964844, 1e-4f);
00627   EXPECT_NEAR ((*sc3ds)[0].descriptor[8], 0, 1e-4f);
00628   EXPECT_NEAR ((*sc3ds)[0].descriptor[21], 39.1745f, 1e-4f);
00629 
00630   EXPECT_NEAR ((*sc3ds)[2].descriptor[4], 0.0f, 1e-4f);
00631   EXPECT_NEAR ((*sc3ds)[2].descriptor[6], 73.7986f, 1e-4f);
00632   EXPECT_NEAR ((*sc3ds)[2].descriptor[7], 209.97763061523438, 1e-4f);
00633   EXPECT_NEAR ((*sc3ds)[2].descriptor[9], 68.5553f, 1e-4f);
00634   EXPECT_NEAR ((*sc3ds)[2].descriptor[16], 0.0f, 1e-4f);
00635   EXPECT_NEAR ((*sc3ds)[2].descriptor[17], 0.0f, 1e-4f);
00636   EXPECT_NEAR ((*sc3ds)[2].descriptor[18], 0.0f, 1e-4f);
00637   EXPECT_NEAR ((*sc3ds)[2].descriptor[20], 0.0f, 1e-4f);
00638   EXPECT_NEAR ((*sc3ds)[2].descriptor[21], 39.1745f, 1e-4f);
00639   EXPECT_NEAR ((*sc3ds)[2].descriptor[22], 154.2060f, 1e-4f);
00640   EXPECT_NEAR ((*sc3ds)[2].descriptor[23], 275.63433837890625, 1e-4f);
00641 
00642   // Test results when setIndices and/or setSearchSurface are used
00643   boost::shared_ptr<vector<int> > test_indices (new vector<int> (0));
00644   for (size_t i = 0; i < cloud.size (); i++)
00645     test_indices->push_back (static_cast<int> (i));
00646 
00647   testSHOTIndicesAndSearchSurface<ShapeContext3DEstimation<PointXYZ, Normal, SHOT>, PointXYZ, Normal, SHOT> (cloudptr, normals, test_indices);
00648 }
00649 
00651 TEST (PCL, USCEstimation)
00652 {
00653   float meshRes = 0.002f;
00654   size_t nBinsL = 4;
00655   size_t nBinsK = 4;
00656   size_t nBinsJ = 4;
00657   float radius = 20.0f * meshRes;
00658   float rmin = radius / 10.0f;
00659   float ptDensityRad = radius / 5.0f;
00660 
00661   // estimate
00662   UniqueShapeContext<PointXYZ, SHOT> uscd;
00663   uscd.setInputCloud (cloud.makeShared ());
00664   uscd.setSearchMethod (tree);
00665   uscd.setRadiusSearch (radius);
00666   uscd.setAzimuthBins (nBinsL);
00667   uscd.setElevationBins (nBinsK);
00668   uscd.setRadiusBins (nBinsJ);
00669   uscd.setMinimalRadius (rmin);
00670   uscd.setPointDensityRadius (ptDensityRad);
00671   uscd.setLocalRadius (radius);
00672   // Compute the features
00673   PointCloud<SHOT>::Ptr uscds (new PointCloud<SHOT>);
00674   uscd.compute (*uscds);
00675   EXPECT_EQ (uscds->size (), cloud.size ());
00676 
00677   EXPECT_NEAR ((*uscds)[0].rf[0], 0.9876f, 1e-4f);
00678   EXPECT_NEAR ((*uscds)[0].rf[1], -0.1408f, 1e-4f);
00679   EXPECT_NEAR ((*uscds)[0].rf[2], -0.06949f, 1e-4f);
00680   EXPECT_NEAR ((*uscds)[0].rf[3], -0.06984f, 1e-4f);
00681   EXPECT_NEAR ((*uscds)[0].rf[4], -0.7904f, 1e-4f);
00682   EXPECT_NEAR ((*uscds)[0].rf[5], 0.6086f, 1e-4f);
00683   EXPECT_NEAR ((*uscds)[0].rf[6], -0.1406f, 1e-4f);
00684   EXPECT_NEAR ((*uscds)[0].rf[7], -0.5962f, 1e-4f);
00685   EXPECT_NEAR ((*uscds)[0].rf[8], -0.7904f, 1e-4f);
00686 
00687   EXPECT_EQ ((*uscds)[0].descriptor.size (), 64);
00688   EXPECT_NEAR ((*uscds)[0].descriptor[4], 52.2474f, 1e-4f);
00689   EXPECT_NEAR ((*uscds)[0].descriptor[5], 39.1745f, 1e-4f);
00690   EXPECT_NEAR ((*uscds)[0].descriptor[6], 176.2354f, 1e-4f);
00691   EXPECT_NEAR ((*uscds)[0].descriptor[7], 199.4478f, 1e-4f);
00692   EXPECT_NEAR ((*uscds)[0].descriptor[8], 0.0f, 1e-4f);
00693 
00694   EXPECT_NEAR ((*uscds)[2].descriptor[6], 110.1472f, 1e-4f);
00695   EXPECT_NEAR ((*uscds)[2].descriptor[7], 145.5597f, 1e-4f);
00696   EXPECT_NEAR ((*uscds)[2].descriptor[8], 69.6632f, 1e-4f);
00697   EXPECT_NEAR ((*uscds)[2].descriptor[22], 57.2765f, 1e-4f);
00698   EXPECT_NEAR ((*uscds)[2].descriptor[23], 172.8134f, 1e-4f);
00699   EXPECT_NEAR ((*uscds)[2].descriptor[25], 68.5554f, 1e-4f);
00700   EXPECT_NEAR ((*uscds)[2].descriptor[26], 0.0f, 1e-4f);
00701   EXPECT_NEAR ((*uscds)[2].descriptor[27], 0.0f, 1e-4f);
00702   EXPECT_NEAR ((*uscds)[2].descriptor[37], 39.1745f, 1e-4f);
00703   EXPECT_NEAR ((*uscds)[2].descriptor[38], 71.5957f, 1e-4f);
00704 
00705   // Test results when setIndices and/or setSearchSurface are used
00706   boost::shared_ptr<vector<int> > test_indices (new vector<int> (0));
00707   for (size_t i = 0; i < cloud.size (); i+=3)
00708     test_indices->push_back (static_cast<int> (i));
00709 
00710   PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
00711   testSHOTIndicesAndSearchSurface<UniqueShapeContext<PointXYZ, SHOT>, PointXYZ, Normal, SHOT> (cloud.makeShared (), normals, test_indices);
00712 }
00713 
00714 #ifndef PCL_ONLY_CORE_POINT_TYPES
00715 
00716   template <> UniqueShapeContext<PointXYZ, Eigen::MatrixXf>
00717   createSHOTDesc<UniqueShapeContext<PointXYZ, Eigen::MatrixXf>, PointXYZ, Normal, Eigen::MatrixXf> (
00718       const PointCloud<Normal>::Ptr &,
00719       const int,
00720       const int,
00721       const bool,
00722       const bool)
00723   {
00724     UniqueShapeContext<PointXYZ, Eigen::MatrixXf> usc;
00725     usc.setAzimuthBins (4);
00726     usc.setElevationBins (4);
00727     usc.setRadiusBins (4);
00728     usc.setMinimalRadius (0.004);
00729     usc.setPointDensityRadius (0.008);
00730     usc.setLocalRadius (0.04f);
00731     return (usc);
00732   }
00733 
00735   template <> ShapeContext3DEstimation<PointXYZ, Normal, Eigen::MatrixXf>
00736   createSHOTDesc<ShapeContext3DEstimation<PointXYZ, Normal, Eigen::MatrixXf>, PointXYZ, Normal, Eigen::MatrixXf> (
00737       const PointCloud<Normal>::Ptr & normals,
00738       const int,
00739       const int,
00740       const bool,
00741       const bool)
00742   {
00743     ShapeContext3DEstimation<PointXYZ, Normal, Eigen::MatrixXf> sc3d;
00744     sc3d.setAzimuthBins (4);
00745     sc3d.setElevationBins (4);
00746     sc3d.setRadiusBins (4);
00747     sc3d.setMinimalRadius (0.004);
00748     sc3d.setPointDensityRadius (0.008);
00749     sc3d.setInputNormals (normals);
00750     return (sc3d);
00751   }
00752 
00754   template <typename FeatureEstimation, typename PointT, typename NormalT> void
00755   testSHOTIndicesAndSearchSurfaceEigen (const typename PointCloud<PointT>::Ptr & points,
00756                                         const typename PointCloud<NormalT>::Ptr & normals,
00757                                         const boost::shared_ptr<vector<int> > & indices,
00758                                         const int nr_shape_bins = 10,
00759                                         const int nr_color_bins = 30,
00760                                         const bool describe_shape = true,
00761                                         const bool describe_color = false)
00762   {
00763     double radius = 0.04;
00764     //
00765     // Test setIndices and setSearchSurface
00766     //
00767     PointCloud<Eigen::MatrixXf> full_output, output0, output1, output2;
00768 
00769     // Compute for all points and then subsample the results
00770     FeatureEstimation est0 = createSHOTDesc<FeatureEstimation, PointT, NormalT, Eigen::MatrixXf>(normals, nr_shape_bins,nr_color_bins,describe_shape,describe_color);
00771     est0.setSearchMethod (typename search::KdTree<PointT>::Ptr (new search::KdTree<PointT>));
00772     est0.setRadiusSearch (radius);
00773     est0.setInputCloud (points);
00774     est0.computeEigen (full_output);
00775 
00776     output0 = PointCloud<Eigen::MatrixXf> (full_output, *indices);
00777 
00778     // Compute with all points as "search surface" and the specified sub-cloud as "input"
00779     typename PointCloud<PointT>::Ptr subpoints (new PointCloud<PointT>);
00780     copyPointCloud (*points, *indices, *subpoints);
00781     FeatureEstimation est1 = createSHOTDesc<FeatureEstimation, PointT, NormalT, Eigen::MatrixXf>(normals, nr_shape_bins,nr_color_bins,describe_shape,describe_color);
00782     est1.setSearchMethod (typename search::KdTree<PointT>::Ptr (new search::KdTree<PointT>));
00783     est1.setRadiusSearch (radius);
00784     est1.setInputCloud (subpoints);
00785     est1.setSearchSurface (points);
00786     est1.computeEigen (output1);
00787 
00789     FeatureEstimation est2 = createSHOTDesc<FeatureEstimation, PointT, NormalT, Eigen::MatrixXf>(normals, nr_shape_bins,nr_color_bins,describe_shape,describe_color);
00790     est2.setSearchMethod (typename search::KdTree<PointT>::Ptr (new search::KdTree<PointT>));
00791     est2.setRadiusSearch (radius);
00792     est2.setInputCloud (points);
00793     est2.setIndices (indices);
00794     est2.computeEigen (output2);
00795 
00796     // All three of the above cases should produce equivalent results
00797     ASSERT_EQ (output0.points.rows (), output1.points.rows ());
00798     ASSERT_EQ (output1.points.rows (), output2.points.rows ());
00799     for (int i = 0; i < output1.points.rows (); ++i)
00800     {
00801       for (int j = 0; j < output0.points.cols (); ++j)
00802       {
00803         ASSERT_EQ (output0.points (i, j), output1.points (i, j));
00804         ASSERT_EQ (output1.points (i, j), output2.points (i, j));
00805       }
00806     }
00807 
00808     //
00809     // Test the combination of setIndices and setSearchSurface
00810     //
00811     PointCloud<Eigen::MatrixXf> output3, output4;
00812 
00813     boost::shared_ptr<vector<int> > indices2 (new vector<int> (0));
00814     for (size_t i = 0; i < (indices->size ()/2); ++i)
00815       indices2->push_back (static_cast<int> (i));
00816 
00817     // Compute with all points as search surface + the specified sub-cloud as "input" but for only a subset of indices
00818     FeatureEstimation est3 = createSHOTDesc<FeatureEstimation, PointT, NormalT, Eigen::MatrixXf>(normals, nr_shape_bins,nr_color_bins,describe_shape,describe_color);
00819     est3.setSearchMethod (typename search::KdTree<PointT>::Ptr (new search::KdTree<PointT>));
00820     est3.setRadiusSearch (0.04);
00821     est3.setSearchSurface (points);
00822     est3.setInputCloud (subpoints);
00823     est3.setIndices (indices2);
00824     est3.computeEigen (output3);
00825 
00826     // Start with features for each point in "subpoints" and then subsample the results
00827     output4 = PointCloud<Eigen::MatrixXf> (output0, *indices2);
00828 
00829     // The two cases above should produce equivalent results
00830     ASSERT_EQ (output3.points.rows (), output4.points.rows ());
00831     for (int i = 0; i < output3.points.rows (); ++i)
00832       for (int j = 0; j < output3.points.cols (); ++j)
00833         ASSERT_EQ (output3.points (i, j), output4.points (i, j));
00834   }
00835 
00837   TEST (PCL, SHOTShapeEstimationEigen)
00838   {
00839     // Estimate normals first
00840     double mr = 0.002;
00841     NormalEstimation<PointXYZ, Normal> n;
00842     PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
00843     // set parameters
00844     n.setInputCloud (cloud.makeShared ());
00845     boost::shared_ptr<vector<int> > indicesptr (new vector<int> (indices));
00846     n.setIndices (indicesptr);
00847     n.setSearchMethod (tree);
00848     n.setRadiusSearch (20 * mr);
00849     n.compute (*normals);
00850 
00851     EXPECT_NEAR (normals->points[103].normal_x, 0.36683175, 1e-4);
00852     EXPECT_NEAR (normals->points[103].normal_y, -0.44696972, 1e-4);
00853     EXPECT_NEAR (normals->points[103].normal_z, -0.81587529, 1e-4);
00854     EXPECT_NEAR (normals->points[200].normal_x, -0.71414840, 1e-4);
00855     EXPECT_NEAR (normals->points[200].normal_y, -0.06002361, 1e-4);
00856     EXPECT_NEAR (normals->points[200].normal_z, -0.69741613, 1e-4);
00857 
00858     EXPECT_NEAR (normals->points[140].normal_x, -0.45109111, 1e-4);
00859     EXPECT_NEAR (normals->points[140].normal_y, -0.19499126, 1e-4);
00860     EXPECT_NEAR (normals->points[140].normal_z, -0.87091631, 1e-4);
00861 
00862     SHOTEstimation<PointXYZ, Normal, Eigen::MatrixXf> shot;
00863     shot.setInputNormals (normals);
00864     EXPECT_EQ (shot.getInputNormals (), normals);
00865     shot.setRadiusSearch (20 * mr);
00866 
00867     // Object
00868     PointCloud<Eigen::MatrixXf>::Ptr shots (new PointCloud<Eigen::MatrixXf>);
00869 
00870     // set parameters
00871     shot.setInputCloud (cloud.makeShared ());
00872     shot.setIndices (indicesptr);
00873     shot.setSearchMethod (tree);
00874 
00875     // estimate
00876     shot.computeEigen (*shots);
00877     EXPECT_EQ (shots->points.rows (), indices.size ());
00878 
00879     EXPECT_NEAR (shots->points (103, 9 ), 0.0072018504, 1e-4);
00880     EXPECT_NEAR (shots->points (103, 10), 0.0023103887, 1e-4);
00881     EXPECT_NEAR (shots->points (103, 11), 0.0024724449, 1e-4);
00882     EXPECT_NEAR (shots->points (103, 19), 0.0031367359, 1e-4);
00883     EXPECT_NEAR (shots->points (103, 20), 0.17439659, 1e-4);
00884     EXPECT_NEAR (shots->points (103, 21), 0.070665278, 1e-4);
00885     EXPECT_NEAR (shots->points (103, 42), 0.013304681, 1e-4);
00886     EXPECT_NEAR (shots->points (103, 53), 0.0073520984, 1e-4);
00887     EXPECT_NEAR (shots->points (103, 54), 0.013584172, 1e-4);
00888     EXPECT_NEAR (shots->points (103, 55), 0.0050609680, 1e-4);
00889 
00890     // Test results when setIndices and/or setSearchSurface are used
00891     boost::shared_ptr<vector<int> > test_indices (new vector<int> (0));
00892     for (size_t i = 0; i < cloud.points.size (); i+=3)
00893       test_indices->push_back (static_cast<int> (i));
00894 
00895     testSHOTIndicesAndSearchSurfaceEigen<SHOTEstimation<PointXYZ, Normal, Eigen::MatrixXf>, PointXYZ, Normal> (cloud.makeShared (), normals, test_indices);
00896 
00897   }
00898 
00900   TEST (PCL, GenericSHOTShapeEstimationEigen)
00901   {
00902     // SHOT length
00903     const int shapeStep_ = 20;
00904     //const int dim = 32*(shapeStep_+1);
00905 
00906     // Estimate normals first
00907     double mr = 0.002;
00908     NormalEstimation<PointXYZ, Normal> n;
00909     PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
00910     // set parameters
00911     n.setInputCloud (cloud.makeShared ());
00912     boost::shared_ptr<vector<int> > indicesptr (new vector<int> (indices));
00913     n.setIndices (indicesptr);
00914     n.setSearchMethod (tree);
00915     n.setRadiusSearch (20 * mr);
00916     n.compute (*normals);
00917 
00918     SHOTEstimation<PointXYZ, Normal, Eigen::MatrixXf> shot (shapeStep_);
00919     shot.setInputNormals (normals);
00920     EXPECT_EQ (shot.getInputNormals (), normals);
00921 
00922     shot.setRadiusSearch (20 * mr);
00923 
00924     PointCloud<Eigen::MatrixXf>::Ptr shots (new PointCloud<Eigen::MatrixXf>);
00925 
00926     // set parameters
00927     shot.setInputCloud (cloud.makeShared ());
00928     shot.setIndices (indicesptr);
00929     shot.setSearchMethod (tree);
00930 
00931     // estimate
00932     shot.computeEigen (*shots);
00933     EXPECT_EQ (shots->points.rows (), indices.size ());
00934 
00935     EXPECT_NEAR (shots->points (103, 18), 0.0077019366, 1e-5);
00936     EXPECT_NEAR (shots->points (103, 19), 0.0024708188, 1e-5);
00937     EXPECT_NEAR (shots->points (103, 21), 0.0079652183, 1e-5);
00938     EXPECT_NEAR (shots->points (103, 38), 0.0067090928, 1e-5);
00939     EXPECT_NEAR (shots->points (103, 39), 0.17498907, 1e-5);
00940     EXPECT_NEAR (shots->points (103, 40), 0.078413926, 1e-5);
00941     EXPECT_NEAR (shots->points (103, 81), 0.014228539, 1e-5);
00942     EXPECT_NEAR (shots->points (103, 103), 0.022390056, 1e-5);
00943     EXPECT_NEAR (shots->points (103, 105), 0.0058866320, 1e-5);
00944     EXPECT_NEAR (shots->points (103, 123), 0.019105887, 1e-5);
00945 
00946     // Test results when setIndices and/or setSearchSurface are used
00947     boost::shared_ptr<vector<int> > test_indices (new vector<int> (0));
00948     for (size_t i = 0; i < cloud.size (); i+=3)
00949       test_indices->push_back (static_cast<int> (i));
00950 
00951     testSHOTIndicesAndSearchSurfaceEigen<SHOTEstimation<PointXYZ, Normal, Eigen::MatrixXf>, PointXYZ, Normal> (cloud.makeShared (), normals, test_indices, shapeStep_);
00952   }
00953 
00955   TEST (PCL, SHOTShapeAndColorEstimationEigen)
00956   {
00957     double mr = 0.002;
00958     // Estimate normals first
00959     NormalEstimation<PointXYZ, Normal> n;
00960     PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
00961     // set parameters
00962     n.setInputCloud (cloud.makeShared ());
00963     boost::shared_ptr<vector<int> > indicesptr (new vector<int> (indices));
00964     n.setIndices (indicesptr);
00965     n.setSearchMethod (tree);
00966     n.setRadiusSearch (20 * mr);
00967     n.compute (*normals);
00968 
00969     search::KdTree<PointXYZRGBA>::Ptr rgbaTree;
00970     rgbaTree.reset (new search::KdTree<PointXYZRGBA> (false));
00971 
00972     // Object
00973     SHOTEstimation<PointXYZRGBA, Normal, Eigen::MatrixXf> shot (true, true);
00974     shot.setInputNormals (normals);
00975     EXPECT_EQ (shot.getInputNormals (), normals);
00976 
00977     shot.setRadiusSearch (20 * mr);
00978 
00979     // Create fake point cloud with colors
00980     PointCloud<PointXYZRGBA> cloudWithColors;
00981     for (int i = 0; i < static_cast<int> (cloud.points.size ()); ++i)
00982     {
00983       PointXYZRGBA p;
00984       p.x = cloud.points[i].x;
00985       p.y = cloud.points[i].y;
00986       p.z = cloud.points[i].z;
00987 
00988       p.rgba = ( (i%255) << 16 ) + ( ( (255 - i ) %255) << 8) + ( ( i*37 ) %255);
00989       cloudWithColors.push_back (p);
00990     }
00991 
00992     rgbaTree->setInputCloud (cloudWithColors.makeShared ());
00993     PointCloud<Eigen::MatrixXf>::Ptr shots (new PointCloud<Eigen::MatrixXf>);
00994 
00995     shot.setInputCloud (cloudWithColors.makeShared ());
00996     shot.setIndices (indicesptr);
00997     shot.setSearchMethod (rgbaTree);
00998 
00999     // estimate
01000     shot.computeEigen (*shots);
01001     EXPECT_EQ (shots->points.rows (), indices.size ());
01002 
01003     EXPECT_NEAR (shots->points (103, 10), 0.0020453099, 1e-5);
01004     EXPECT_NEAR (shots->points (103, 11), 0.0021887729, 1e-5);
01005     EXPECT_NEAR (shots->points (103, 21), 0.062557608, 1e-5);
01006     EXPECT_NEAR (shots->points (103, 42), 0.011778189, 1e-5);
01007     EXPECT_NEAR (shots->points (103, 53), 0.0065085669, 1e-5);
01008     EXPECT_NEAR (shots->points (103, 54), 0.012025614, 1e-5);
01009     EXPECT_NEAR (shots->points (103, 55), 0.0044803056, 1e-5);
01010     EXPECT_NEAR (shots->points (103, 64), 0.064429596, 1e-5);
01011     EXPECT_NEAR (shots->points (103, 65), 0.046486385, 1e-5);
01012     EXPECT_NEAR (shots->points (103, 86), 0.011518310, 1e-5);
01013 
01014     EXPECT_NEAR (shots->points (103, 357), 0.0020453099, 1e-5);
01015     EXPECT_NEAR (shots->points (103, 360), 0.0027993850, 1e-5);
01016     EXPECT_NEAR (shots->points (103, 386), 0.045115642, 1e-5);
01017     EXPECT_NEAR (shots->points (103, 387), 0.059068538, 1e-5);
01018     EXPECT_NEAR (shots->points (103, 389), 0.0047547864, 1e-5);
01019     EXPECT_NEAR (shots->points (103, 453), 0.0051176427, 1e-5);
01020     EXPECT_NEAR (shots->points (103, 481), 0.0053625242, 1e-5);
01021     EXPECT_NEAR (shots->points (103, 482), 0.012025614, 1e-5);
01022     EXPECT_NEAR (shots->points (103, 511), 0.0057367259, 1e-5);
01023     EXPECT_NEAR (shots->points (103, 512), 0.048357654, 1e-5);
01024 
01025     // Test results when setIndices and/or setSearchSurface are used
01026     boost::shared_ptr<vector<int> > test_indices (new vector<int> (0));
01027     for (size_t i = 0; i < cloud.size (); i+=3)
01028       test_indices->push_back (static_cast<int> (i));
01029 
01030     testSHOTIndicesAndSearchSurfaceEigen<SHOTEstimation<PointXYZRGBA, Normal, Eigen::MatrixXf>, PointXYZRGBA, Normal> (cloudWithColors.makeShared (), normals, test_indices);
01031   }
01032 
01034   TEST (PCL, 3DSCEstimationEigen)
01035   {
01036     float meshRes = 0.002f;
01037     size_t nBinsL = 4;
01038     size_t nBinsK = 4;
01039     size_t nBinsJ = 4;
01040     float radius = 20.0f * meshRes;
01041     float rmin = radius / 10.0f;
01042     float ptDensityRad = radius / 5.0f;
01043 
01044     PointCloud<PointXYZ>::Ptr cloudptr = cloud.makeShared ();
01045 
01046     // Estimate normals first
01047     NormalEstimation<PointXYZ, Normal> ne;
01048     PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
01049     // set parameters
01050     ne.setInputCloud (cloudptr);
01051     ne.setSearchMethod (tree);
01052     ne.setRadiusSearch (radius);
01053     // estimate
01054     ne.compute (*normals);
01055     ShapeContext3DEstimation<PointXYZ, Normal, Eigen::MatrixXf> sc3d;
01056     sc3d.setInputCloud (cloudptr);
01057     sc3d.setInputNormals (normals);
01058     sc3d.setSearchMethod (tree);
01059     sc3d.setRadiusSearch (radius);
01060     sc3d.setAzimuthBins (nBinsL);
01061     sc3d.setElevationBins (nBinsK);
01062     sc3d.setRadiusBins (nBinsJ);
01063     sc3d.setMinimalRadius (rmin);
01064     sc3d.setPointDensityRadius (ptDensityRad);
01065     // Compute the features
01066     PointCloud<Eigen::MatrixXf>::Ptr sc3ds (new PointCloud<Eigen::MatrixXf>);
01067     sc3d.computeEigen (*sc3ds);
01068     EXPECT_EQ (sc3ds->points.rows (), cloud.size ());
01069 
01070     // 3DSC does not define a repeatable local RF, we set it to zero to signal it to the user
01071     //EXPECT_NEAR ((*sc3ds)[0].rf[0], 0.2902f, 1e-4f);
01072     //EXPECT_NEAR ((*sc3ds)[0].rf[1], 0.7334f, 1e-4f);
01073     //EXPECT_NEAR ((*sc3ds)[0].rf[2], -0.6146f, 1e-4f);
01074     //EXPECT_NEAR ((*sc3ds)[0].rf[3], 0.9486f, 1e-4f);
01075     //EXPECT_NEAR ((*sc3ds)[0].rf[4], -0.3051f, 1e-4f);
01076     //EXPECT_NEAR ((*sc3ds)[0].rf[5], 0.0838f, 1e-4f);
01077     //EXPECT_NEAR ((*sc3ds)[0].rf[6], -0.1261f, 1e-4f);
01078     //EXPECT_NEAR ((*sc3ds)[0].rf[7], -0.6074f, 1e-4f);
01079     //EXPECT_NEAR ((*sc3ds)[0].rf[8], -0.7843f, 1e-4f);
01080 
01081     EXPECT_NEAR (sc3ds->points (0, 0), 0.0f, 1e-4f);
01082     EXPECT_NEAR (sc3ds->points (0, 1), 0.0f, 1e-4f);
01083     EXPECT_NEAR (sc3ds->points (0, 2), 0.0f, 1e-4f);
01084     EXPECT_NEAR (sc3ds->points (0, 3), 0.0f, 1e-4f);
01085     EXPECT_NEAR (sc3ds->points (0, 4), 0.0f, 1e-4f);
01086     EXPECT_NEAR (sc3ds->points (0, 5), 0.0f, 1e-4f);
01087     EXPECT_NEAR (sc3ds->points (0, 6), 0.0f, 1e-4f);
01088     EXPECT_NEAR (sc3ds->points (0, 7), 0.0f, 1e-4f);
01089     EXPECT_NEAR (sc3ds->points (0, 8), 0.0f, 1e-4f);
01090 
01091     EXPECT_EQ   (sc3ds->points.row (0).size (), 64 + 9);
01092     EXPECT_NEAR (sc3ds->points (0, 9 + 4), 52.2474f, 1e-4f);
01093     EXPECT_NEAR (sc3ds->points (0, 9 + 6), 150.901611328125, 1e-4f);
01094     EXPECT_NEAR (sc3ds->points (0, 9 + 7), 169.09703063964844, 1e-4f);
01095     EXPECT_NEAR (sc3ds->points (0, 9 + 8), 0, 1e-4f);
01096     EXPECT_NEAR (sc3ds->points (0, 9 + 21), 39.1745f, 1e-4f);
01097 
01098     EXPECT_NEAR (sc3ds->points (2, 9 + 4), 0.0f, 1e-4f);
01099     EXPECT_NEAR (sc3ds->points (2, 9 + 6), 73.7986f, 1e-4f);
01100     EXPECT_NEAR (sc3ds->points (2, 9 + 7), 209.97763061523438, 1e-4f);
01101 
01102     EXPECT_NEAR (sc3ds->points (2, 9 + 9), 68.5553f, 1e-4f);
01103     EXPECT_NEAR (sc3ds->points (2, 9 + 16), 0.0f, 1e-4f);
01104     EXPECT_NEAR (sc3ds->points (2, 9 + 17), 0.0f, 1e-4f);
01105     EXPECT_NEAR (sc3ds->points (2, 9 + 18), 0.0f, 1e-4f);
01106     EXPECT_NEAR (sc3ds->points (2, 9 + 20), 0.0f, 1e-4f);
01107 
01108     EXPECT_NEAR (sc3ds->points (2, 9 + 21), 39.1745f, 1e-4f);
01109     EXPECT_NEAR (sc3ds->points (2, 9 + 22), 154.2060f, 1e-4f);
01110     EXPECT_NEAR (sc3ds->points (2, 9 + 23), 275.63433837890625, 1e-4f);
01111 
01112     // Test results when setIndices and/or setSearchSurface are used
01113     boost::shared_ptr<vector<int> > test_indices (new vector<int> (0));
01114     for (size_t i = 0; i < cloud.size (); i++)
01115       test_indices->push_back (static_cast<int> (i));
01116 
01117     testSHOTIndicesAndSearchSurfaceEigen<ShapeContext3DEstimation<PointXYZ, Normal, Eigen::MatrixXf>, PointXYZ, Normal> (cloudptr, normals, test_indices);
01118   }
01119 
01121   TEST (PCL, USCEstimationEigen)
01122   {
01123     float meshRes = 0.002f;
01124     size_t nBinsL = 4;
01125     size_t nBinsK = 4;
01126     size_t nBinsJ = 4;
01127     float radius = 20.0f * meshRes;
01128     float rmin = radius / 10.0f;
01129     float ptDensityRad = radius / 5.0f;
01130 
01131     // estimate
01132     UniqueShapeContext<PointXYZ, Eigen::MatrixXf> uscd;
01133     uscd.setInputCloud (cloud.makeShared ());
01134     uscd.setSearchMethod (tree);
01135     uscd.setRadiusSearch (radius);
01136     uscd.setAzimuthBins (nBinsL);
01137     uscd.setElevationBins (nBinsK);
01138     uscd.setRadiusBins (nBinsJ);
01139     uscd.setMinimalRadius (rmin);
01140     uscd.setPointDensityRadius (ptDensityRad);
01141     uscd.setLocalRadius (radius);
01142     // Compute the features
01143     PointCloud<Eigen::MatrixXf>::Ptr uscds (new PointCloud<Eigen::MatrixXf>);
01144     uscd.computeEigen (*uscds);
01145     EXPECT_EQ (uscds->points.rows (), cloud.size ());
01146 
01147     EXPECT_NEAR (uscds->points (0, 0), 0.9876f, 1e-4f);
01148     EXPECT_NEAR (uscds->points (0, 1), -0.1408f, 1e-4f);
01149     EXPECT_NEAR (uscds->points (0, 2), -0.06949f, 1e-4f);
01150     EXPECT_NEAR (uscds->points (0, 3), -0.06984f, 1e-4f);
01151     EXPECT_NEAR (uscds->points (0, 4), -0.7904f, 1e-4f);
01152     EXPECT_NEAR (uscds->points (0, 5), 0.6086f, 1e-4f);
01153     EXPECT_NEAR (uscds->points (0, 6), -0.1406f, 1e-4f);
01154     EXPECT_NEAR (uscds->points (0, 7), -0.5962f, 1e-4f);
01155     EXPECT_NEAR (uscds->points (0, 8), -0.7904f, 1e-4f);
01156 
01157     EXPECT_EQ   (uscds->points.row (0).size (), 9+64);
01158     EXPECT_NEAR (uscds->points (0, 9 + 4), 52.2474f, 1e-4f);
01159     EXPECT_NEAR (uscds->points (0, 9 + 5), 39.1745f, 1e-4f);
01160     EXPECT_NEAR (uscds->points (0, 9 + 6), 176.2354f, 1e-4f);
01161     EXPECT_NEAR (uscds->points (0, 9 + 7), 199.4478f, 1e-4f);
01162     EXPECT_NEAR (uscds->points (0, 9 + 8), 0.0f, 1e-4f);
01163 
01164     EXPECT_NEAR (uscds->points (2, 9 + 6), 110.1472f, 1e-4f);
01165     EXPECT_NEAR (uscds->points (2, 9 + 7), 145.5597f, 1e-4f);
01166     EXPECT_NEAR (uscds->points (2, 9 + 8), 69.6632f, 1e-4f);
01167     EXPECT_NEAR (uscds->points (2, 9 + 22), 57.2765f, 1e-4f);
01168     EXPECT_NEAR (uscds->points (2, 9 + 23), 172.8134f, 1e-4f);
01169     EXPECT_NEAR (uscds->points (2, 9 + 25), 68.5554f, 1e-4f);
01170     EXPECT_NEAR (uscds->points (2, 9 + 26), 0.0f, 1e-4f);
01171     EXPECT_NEAR (uscds->points (2, 9 + 27), 0.0f, 1e-4f);
01172     EXPECT_NEAR (uscds->points (2, 9 + 37), 39.1745f, 1e-4f);
01173     EXPECT_NEAR (uscds->points (2, 9 + 38), 71.5957f, 1e-4f);
01174 
01175     // Test results when setIndices and/or setSearchSurface are used
01176     boost::shared_ptr<vector<int> > test_indices (new vector<int> (0));
01177     for (size_t i = 0; i < cloud.size (); i+=3)
01178       test_indices->push_back (static_cast<int> (i));
01179 
01180     PointCloud<Normal>::Ptr normals (new PointCloud<Normal> ());
01181     testSHOTIndicesAndSearchSurfaceEigen<UniqueShapeContext<PointXYZ, Eigen::MatrixXf>, PointXYZ, Normal> (cloud.makeShared (), normals, test_indices);
01182   }
01183 #endif
01184 
01185 /* ---[ */
01186 int
01187 main (int argc, char** argv)
01188 {
01189   if (argc < 2)
01190   {
01191     std::cerr << "No test file given. Please download `bun0.pcd` and pass its path to the test." << std::endl;
01192     return (-1);
01193   }
01194 
01195   if (loadPCDFile<PointXYZ> (argv[1], cloud) < 0)
01196   {
01197     std::cerr << "Failed to read test file. Please download `bun0.pcd` and pass its path to the test." << std::endl;
01198     return (-1);
01199   }
01200 
01201   indices.resize (cloud.points.size ());
01202   for (size_t i = 0; i < indices.size (); ++i)
01203     indices[i] = static_cast<int> (i);
01204 
01205   tree.reset (new search::KdTree<PointXYZ> (false));
01206   tree->setInputCloud (cloud.makeShared ());
01207 
01208   testing::InitGoogleTest (&argc, argv);
01209   return (RUN_ALL_TESTS ());
01210 }
01211 /* ]--- */


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