mesh_filter_test.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2013, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00035 
00036 #include <gtest/gtest.h>
00037 #include <moveit/mesh_filter/mesh_filter.h>
00038 #include <moveit/mesh_filter/stereo_camera_model.h>
00039 #include <geometric_shapes/shapes.h>
00040 #include <geometric_shapes/shape_operations.h>
00041 #include <eigen3/Eigen/Eigen>
00042 #include <vector>
00043 
00044 using namespace mesh_filter;
00045 using namespace Eigen;
00046 using namespace std;
00047 using namespace boost;
00048 
00049 namespace mesh_filter_test
00050 {
00051 
00052 template<typename Type> inline const Type getRandomNumber (const Type& min, const Type& max)
00053 {
00054   return Type(min + (max-min) * double(rand ()) / double(RAND_MAX));
00055 }
00056 
00057 template<typename Type>
00058 class FilterTraits
00059 {
00060   public:
00061     static const GLushort GL_TYPE = GL_ZERO;
00062 };
00063 
00064 template<>
00065 class FilterTraits<unsigned short>
00066 {
00067   public:
00068     static const GLushort GL_TYPE = GL_UNSIGNED_SHORT;
00069     static const double ToMetricScale = 0.001;
00070 };
00071 
00072 template<>
00073 class FilterTraits<float>
00074 {
00075   public:
00076     static const GLushort GL_TYPE = GL_FLOAT;
00077     static const double ToMetricScale = 1.0f;
00078 };
00079 
00080 template<typename Type>
00081 class MeshFilterTest : public testing::TestWithParam <double>
00082 {
00083   BOOST_STATIC_ASSERT_MSG (FilterTraits<Type>::GL_TYPE != GL_ZERO, "Only \"float\" and \"unsigned short int\" are allowed.");
00084   public:
00085     MeshFilterTest (unsigned width = 500, unsigned height = 500, double near = 0.5, double far = 5.0, double shadow = 0.1, double epsilon = 1e-7);
00086     void test ();
00087     void setMeshDistance (double distance) { distance_ = distance; }
00088   private:
00089     shapes::Mesh createMesh (double z) const;
00090     bool transform_callback (MeshHandle handle, Affine3d& transform) const;
00091     void getGroundTruth (unsigned int* labels, float* depth) const;
00092     const unsigned int width_;
00093     const unsigned int height_;
00094     const double near_;
00095     const double far_;
00096     const double shadow_;
00097     const double epsilon_;
00098     StereoCameraModel::Parameters sensor_parameters_;
00099     MeshFilter<StereoCameraModel> filter_;
00100     MeshHandle handle_;
00101     vector<Type> sensor_data_;
00102     double distance_;
00103 };
00104 
00105 template<typename Type>
00106 MeshFilterTest<Type>::MeshFilterTest (unsigned width, unsigned height, double near, double far, double shadow, double epsilon)
00107 : width_ (width)
00108 , height_ (height)
00109 , near_ (near)
00110 , far_ (far)
00111 , shadow_ (shadow)
00112 , epsilon_ (epsilon)
00113 , sensor_parameters_ (width, height, near_, far_, width >> 1, height >> 1, width >> 1, height >> 1, 0.1, 0.1)
00114 , filter_ (boost::bind(&MeshFilterTest<Type>::transform_callback, this, _1, _2), sensor_parameters_)
00115 , sensor_data_ (width_ * height_)
00116 , distance_ (0.0)
00117 {
00118   filter_.setShadowThreshold (shadow_);
00119   // no padding
00120   filter_.setPaddingOffset (0.0);
00121   filter_.setPaddingScale (0.0);
00122 
00123   // create a large plane that covers the whole visible area -> no boundaries
00124 
00125   shapes::Mesh mesh = createMesh (0);
00126   handle_ = filter_.addMesh (mesh);
00127 
00128   // make it random but reproducable
00129   srand (0);
00130   Type t_near = near_ / FilterTraits<Type>::ToMetricScale;
00131   Type t_far = far_ / FilterTraits<Type>::ToMetricScale;
00132   for (typename vector<Type>::iterator sIt = sensor_data_.begin (); sIt != sensor_data_.end (); ++sIt)
00133   {
00134     do {
00135       *sIt = getRandomNumber<Type> (0.0, 10.0 / FilterTraits<Type>::ToMetricScale);
00136     } while (*sIt == t_near || *sIt == t_far);
00137   }
00138 }
00139 
00140 template<typename Type>
00141 shapes::Mesh MeshFilterTest<Type>::createMesh (double z) const
00142 {
00143   shapes::Mesh mesh (4, 4);
00144   mesh.vertices [0]  = -5;
00145   mesh.vertices [1]  = -5;
00146   mesh.vertices [2]  =  z;
00147 
00148   mesh.vertices [3]  = -5;
00149   mesh.vertices [4]  =  5;
00150   mesh.vertices [5]  =  z;
00151 
00152   mesh.vertices [6]  =  5;
00153   mesh.vertices [7]  =  5;
00154   mesh.vertices [8]  =  z;
00155 
00156   mesh.vertices [9]  =  5;
00157   mesh.vertices [10] = -5;
00158   mesh.vertices [11] =  z;
00159 
00160   mesh.triangles [0] = 0;
00161   mesh.triangles [1] = 3;
00162   mesh.triangles [2] = 2;
00163 
00164   mesh.triangles [3] = 0;
00165   mesh.triangles [4] = 2;
00166   mesh.triangles [5] = 1;
00167 
00168   mesh.triangles [6] = 0;
00169   mesh.triangles [7] = 2;
00170   mesh.triangles [8] = 3;
00171 
00172   mesh.triangles [9] = 0;
00173   mesh.triangles [10] = 1;
00174   mesh.triangles [11] = 2;
00175 
00176   mesh.vertex_normals [0] = 0;
00177   mesh.vertex_normals [1] = 0;
00178   mesh.vertex_normals [2] = 1;
00179 
00180   mesh.vertex_normals [3] = 0;
00181   mesh.vertex_normals [4] = 0;
00182   mesh.vertex_normals [5] = 1;
00183 
00184   mesh.vertex_normals [6] = 0;
00185   mesh.vertex_normals [7] = 0;
00186   mesh.vertex_normals [8] = 1;
00187 
00188   mesh.vertex_normals [9] = 0;
00189   mesh.vertex_normals [10] = 0;
00190   mesh.vertex_normals [11] = 1;
00191 
00192   return mesh;
00193 }
00194 
00195 template<typename Type>
00196 bool MeshFilterTest<Type>::transform_callback (MeshHandle handle, Affine3d& transform) const
00197 {
00198   transform = Affine3d::Identity();
00199   if (handle == handle_)
00200     transform.translation () = Vector3d (0, 0, distance_);
00201   return true;
00202 }
00203 
00204 template<typename Type>
00205 void MeshFilterTest<Type>::test ()
00206 {
00207   shapes::Mesh mesh = createMesh (0);
00208   mesh_filter::MeshHandle handle = filter_.addMesh (mesh);
00209   filter_.filter (&sensor_data_[0], FilterTraits<Type>::GL_TYPE, false);
00210 
00211   vector<float> gt_depth (width_ * height_);
00212   vector<unsigned int> gt_labels (width_ * height_);
00213   getGroundTruth (&gt_labels [0], &gt_depth [0]);
00214 
00215   vector<float> filtered_depth (width_ * height_);
00216   vector<unsigned int> filtered_labels (width_ * height_);
00217   filter_.getFilteredDepth (& filtered_depth[0]);
00218   filter_.getFilteredLabels (& filtered_labels[0]);
00219 
00220   for (unsigned idx = 0; idx < width_ * height_; ++idx)
00221   {
00222     // Only test if we are not very close to boundaries of object meshes and shadow-boundaries.
00223     float sensor_depth = sensor_data_ [idx] * FilterTraits<Type>::ToMetricScale;
00224     if (fabs(sensor_depth - distance_ - shadow_) > epsilon_ && fabs(sensor_depth - distance_) > epsilon_)
00225     {
00226 //      if (filtered_labels [idx] != gt_labels [idx])
00227 //      {
00228 //        cout << idx << " :: " <<  filtered_labels [idx] << " vs. " << gt_labels [idx] << " :: " <<  sensor_data_ [idx] << " = " << filtered_depth [idx] << " vs. " << gt_depth [idx] << endl;
00229 //        exit (1);
00230 //      }
00231       EXPECT_FLOAT_EQ (filtered_depth [idx], gt_depth [idx]);
00232       EXPECT_EQ (filtered_labels [idx], gt_labels [idx]);
00233     }
00234   }
00235   filter_.removeMesh (handle);
00236 }
00237 
00238 template<typename Type>
00239 void MeshFilterTest<Type>::getGroundTruth (unsigned int *labels, float* depth) const
00240 {
00241   const double scale = FilterTraits<Type>::ToMetricScale;
00242     if (distance_ <= near_ || distance_ >= far_)
00243   {
00244     // no filtering is done -> no shadow values or label values
00245     for (unsigned yIdx = 0, idx = 0; yIdx < height_; ++yIdx)
00246     {
00247       for (unsigned xIdx = 0; xIdx < width_; ++xIdx, ++idx)
00248       {
00249         depth[idx] = double(sensor_data_ [idx]) * scale;
00250         if (depth[idx] < near_)
00251           labels [idx] = MeshFilterBase::NearClip;
00252         else if (depth[idx] >= far_)
00253           labels [idx] = MeshFilterBase::FarClip;
00254         else
00255           labels [idx] = MeshFilterBase::Background;
00256 
00257         if (depth [idx] <= near_ || depth [idx] >= far_)
00258           depth [idx] = 0;
00259       }
00260     }
00261   }
00262   else
00263   {
00264 
00265     for (unsigned yIdx = 0, idx = 0; yIdx < height_; ++yIdx)
00266     {
00267       for (unsigned xIdx = 0; xIdx < width_; ++xIdx, ++idx)
00268       {
00269         depth[idx] =  double(sensor_data_ [idx]) * scale;
00270 
00271         if (depth [idx] < near_)
00272         {
00273           labels [idx] = MeshFilterBase::NearClip;
00274           depth [idx] = 0;
00275         }
00276         else
00277         {
00278           double diff = depth [idx] - distance_;
00279           if (diff < 0 && depth[idx] < far_)
00280             labels [idx] = MeshFilterBase::Background;
00281           else if (diff > shadow_)
00282             labels [idx] = MeshFilterBase::Shadow;
00283           else if (depth[idx] >= far_)
00284             labels [idx] = MeshFilterBase::FarClip;
00285           else
00286           {
00287             labels [idx] = MeshFilterBase::FirstLabel;
00288             depth [idx] = 0;
00289           }
00290 
00291           if (depth[idx] >= far_)
00292             depth[idx] = 0;
00293         }
00294       }
00295     }
00296   }
00297 }
00298 
00299 } // namespace mesh_filter_test
00300 
00301 typedef mesh_filter_test::MeshFilterTest<float> MeshFilterTestFloat;
00302 TEST_P (MeshFilterTestFloat, float)
00303 {
00304   this->setMeshDistance (this->GetParam ());
00305   this->test ();
00306 }
00307 INSTANTIATE_TEST_CASE_P(float_test, MeshFilterTestFloat, ::testing::Range<double>(0.0f, 6.0f, 0.5f));
00308 
00309 typedef mesh_filter_test::MeshFilterTest<unsigned short> MeshFilterTestUnsignedShort;
00310 TEST_P (MeshFilterTestUnsignedShort, unsigned_short)
00311 {
00312   this->setMeshDistance (this->GetParam ());
00313   this->test ();
00314 }
00315 INSTANTIATE_TEST_CASE_P(ushort_test, MeshFilterTestUnsignedShort, ::testing::Range<double>(0.0f, 6.0f, 0.5f));
00316 
00317 
00318 int main(int argc, char **argv)
00319 {
00320   testing::InitGoogleTest(&argc, argv);
00321   int arg;
00322 
00323   return RUN_ALL_TESTS();
00324 }


perception
Author(s): Ioan Sucan , Jon Binney , Suat Gedikli
autogenerated on Wed Aug 26 2015 12:43:21