00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
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
00120 filter_.setPaddingOffset (0.0);
00121 filter_.setPaddingScale (0.0);
00122
00123
00124
00125 shapes::Mesh mesh = createMesh (0);
00126 handle_ = filter_.addMesh (mesh);
00127
00128
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 (>_labels [0], >_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
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
00227
00228
00229
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
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 }
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 }