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 #include <gtest/gtest.h>
00036 #include <moveit/mesh_filter/mesh_filter.h>
00037 #include <moveit/mesh_filter/stereo_camera_model.h>
00038 #include <geometric_shapes/shapes.h>
00039 #include <geometric_shapes/shape_operations.h>
00040 #include <eigen3/Eigen/Eigen>
00041 #include <vector>
00042
00043 using namespace mesh_filter;
00044 using namespace Eigen;
00045 using namespace std;
00046 using namespace boost;
00047
00048 namespace mesh_filter_test
00049 {
00050 template <typename Type>
00051 inline const Type getRandomNumber(const Type& min, const Type& max)
00052 {
00053 return Type(min + (max - min) * double(rand()) / double(RAND_MAX));
00054 }
00055
00056 template <typename Type>
00057 class FilterTraits
00058 {
00059 public:
00060 static const GLushort FILTER_GL_TYPE = GL_ZERO;
00061 };
00062
00063 template <>
00064 class FilterTraits<unsigned short>
00065 {
00066 public:
00067 static const GLushort FILTER_GL_TYPE = GL_UNSIGNED_SHORT;
00068 static const double ToMetricScale = 0.001;
00069 };
00070
00071 template <>
00072 class FilterTraits<float>
00073 {
00074 public:
00075 static const GLushort FILTER_GL_TYPE = GL_FLOAT;
00076 static const double ToMetricScale = 1.0f;
00077 };
00078
00079 template <typename Type>
00080 class MeshFilterTest : public testing::TestWithParam<double>
00081 {
00082 BOOST_STATIC_ASSERT_MSG(FilterTraits<Type>::FILTER_GL_TYPE != GL_ZERO, "Only \"float\" and \"unsigned short int\" "
00083 "are allowed.");
00084
00085 public:
00086 MeshFilterTest(unsigned width = 500, unsigned height = 500, double near = 0.5, double far = 5.0, double shadow = 0.1,
00087 double epsilon = 1e-7);
00088 void test();
00089 void setMeshDistance(double distance)
00090 {
00091 distance_ = distance;
00092 }
00093
00094 private:
00095 shapes::Mesh createMesh(double z) const;
00096 bool transform_callback(MeshHandle handle, Affine3d& transform) const;
00097 void getGroundTruth(unsigned int* labels, float* depth) const;
00098 const unsigned int width_;
00099 const unsigned int height_;
00100 const double near_;
00101 const double far_;
00102 const double shadow_;
00103 const double epsilon_;
00104 StereoCameraModel::Parameters sensor_parameters_;
00105 MeshFilter<StereoCameraModel> filter_;
00106 MeshHandle handle_;
00107 vector<Type> sensor_data_;
00108 double distance_;
00109 };
00110
00111 template <typename Type>
00112 MeshFilterTest<Type>::MeshFilterTest(unsigned width, unsigned height, double near, double far, double shadow,
00113 double epsilon)
00114 : width_(width)
00115 , height_(height)
00116 , near_(near)
00117 , far_(far)
00118 , shadow_(shadow)
00119 , epsilon_(epsilon)
00120 , sensor_parameters_(width, height, near_, far_, width >> 1, height >> 1, width >> 1, height >> 1, 0.1, 0.1)
00121 , filter_(boost::bind(&MeshFilterTest<Type>::transform_callback, this, _1, _2), sensor_parameters_)
00122 , sensor_data_(width_ * height_)
00123 , distance_(0.0)
00124 {
00125 filter_.setShadowThreshold(shadow_);
00126
00127 filter_.setPaddingOffset(0.0);
00128 filter_.setPaddingScale(0.0);
00129
00130
00131
00132 shapes::Mesh mesh = createMesh(0);
00133 handle_ = filter_.addMesh(mesh);
00134
00135
00136 srand(0);
00137 Type t_near = near_ / FilterTraits<Type>::ToMetricScale;
00138 Type t_far = far_ / FilterTraits<Type>::ToMetricScale;
00139 for (typename vector<Type>::iterator sIt = sensor_data_.begin(); sIt != sensor_data_.end(); ++sIt)
00140 {
00141 do
00142 {
00143 *sIt = getRandomNumber<Type>(0.0, 10.0 / FilterTraits<Type>::ToMetricScale);
00144 } while (*sIt == t_near || *sIt == t_far);
00145 }
00146 }
00147
00148 template <typename Type>
00149 shapes::Mesh MeshFilterTest<Type>::createMesh(double z) const
00150 {
00151 shapes::Mesh mesh(4, 4);
00152 mesh.vertices[0] = -5;
00153 mesh.vertices[1] = -5;
00154 mesh.vertices[2] = z;
00155
00156 mesh.vertices[3] = -5;
00157 mesh.vertices[4] = 5;
00158 mesh.vertices[5] = z;
00159
00160 mesh.vertices[6] = 5;
00161 mesh.vertices[7] = 5;
00162 mesh.vertices[8] = z;
00163
00164 mesh.vertices[9] = 5;
00165 mesh.vertices[10] = -5;
00166 mesh.vertices[11] = z;
00167
00168 mesh.triangles[0] = 0;
00169 mesh.triangles[1] = 3;
00170 mesh.triangles[2] = 2;
00171
00172 mesh.triangles[3] = 0;
00173 mesh.triangles[4] = 2;
00174 mesh.triangles[5] = 1;
00175
00176 mesh.triangles[6] = 0;
00177 mesh.triangles[7] = 2;
00178 mesh.triangles[8] = 3;
00179
00180 mesh.triangles[9] = 0;
00181 mesh.triangles[10] = 1;
00182 mesh.triangles[11] = 2;
00183
00184 mesh.vertex_normals[0] = 0;
00185 mesh.vertex_normals[1] = 0;
00186 mesh.vertex_normals[2] = 1;
00187
00188 mesh.vertex_normals[3] = 0;
00189 mesh.vertex_normals[4] = 0;
00190 mesh.vertex_normals[5] = 1;
00191
00192 mesh.vertex_normals[6] = 0;
00193 mesh.vertex_normals[7] = 0;
00194 mesh.vertex_normals[8] = 1;
00195
00196 mesh.vertex_normals[9] = 0;
00197 mesh.vertex_normals[10] = 0;
00198 mesh.vertex_normals[11] = 1;
00199
00200 return mesh;
00201 }
00202
00203 template <typename Type>
00204 bool MeshFilterTest<Type>::transform_callback(MeshHandle handle, Affine3d& transform) const
00205 {
00206 transform = Affine3d::Identity();
00207 if (handle == handle_)
00208 transform.translation() = Vector3d(0, 0, distance_);
00209 return true;
00210 }
00211
00212 template <typename Type>
00213 void MeshFilterTest<Type>::test()
00214 {
00215 shapes::Mesh mesh = createMesh(0);
00216 mesh_filter::MeshHandle handle = filter_.addMesh(mesh);
00217 filter_.filter(&sensor_data_[0], FilterTraits<Type>::FILTER_GL_TYPE, false);
00218
00219 vector<float> gt_depth(width_ * height_);
00220 vector<unsigned int> gt_labels(width_ * height_);
00221 getGroundTruth(>_labels[0], >_depth[0]);
00222
00223 vector<float> filtered_depth(width_ * height_);
00224 vector<unsigned int> filtered_labels(width_ * height_);
00225 filter_.getFilteredDepth(&filtered_depth[0]);
00226 filter_.getFilteredLabels(&filtered_labels[0]);
00227
00228 for (unsigned idx = 0; idx < width_ * height_; ++idx)
00229 {
00230
00231 float sensor_depth = sensor_data_[idx] * FilterTraits<Type>::ToMetricScale;
00232 if (fabs(sensor_depth - distance_ - shadow_) > epsilon_ && fabs(sensor_depth - distance_) > epsilon_)
00233 {
00234 ASSERT_FLOAT_EQ(filtered_depth[idx], gt_depth[idx]);
00235 ASSERT_EQ(filtered_labels[idx], gt_labels[idx]);
00236 }
00237 }
00238 filter_.removeMesh(handle);
00239 }
00240
00241 template <typename Type>
00242 void MeshFilterTest<Type>::getGroundTruth(unsigned int* labels, float* depth) const
00243 {
00244 const double scale = FilterTraits<Type>::ToMetricScale;
00245 if (distance_ <= near_ || distance_ >= far_)
00246 {
00247
00248 for (unsigned yIdx = 0, idx = 0; yIdx < height_; ++yIdx)
00249 {
00250 for (unsigned xIdx = 0; xIdx < width_; ++xIdx, ++idx)
00251 {
00252 depth[idx] = double(sensor_data_[idx]) * scale;
00253 if (depth[idx] < near_)
00254 labels[idx] = MeshFilterBase::NearClip;
00255 else if (depth[idx] >= far_)
00256 labels[idx] = MeshFilterBase::FarClip;
00257 else
00258 labels[idx] = MeshFilterBase::Background;
00259
00260 if (depth[idx] <= near_ || depth[idx] >= far_)
00261 depth[idx] = 0;
00262 }
00263 }
00264 }
00265 else
00266 {
00267 for (unsigned yIdx = 0, idx = 0; yIdx < height_; ++yIdx)
00268 {
00269 for (unsigned xIdx = 0; xIdx < width_; ++xIdx, ++idx)
00270 {
00271 depth[idx] = double(sensor_data_[idx]) * scale;
00272
00273 if (depth[idx] < near_)
00274 {
00275 labels[idx] = MeshFilterBase::NearClip;
00276 depth[idx] = 0;
00277 }
00278 else
00279 {
00280 double diff = depth[idx] - distance_;
00281 if (diff < 0 && depth[idx] < far_)
00282 labels[idx] = MeshFilterBase::Background;
00283 else if (diff > shadow_)
00284 labels[idx] = MeshFilterBase::Shadow;
00285 else if (depth[idx] >= far_)
00286 labels[idx] = MeshFilterBase::FarClip;
00287 else
00288 {
00289 labels[idx] = MeshFilterBase::FirstLabel;
00290 depth[idx] = 0;
00291 }
00292
00293 if (depth[idx] >= far_)
00294 depth[idx] = 0;
00295 }
00296 }
00297 }
00298 }
00299 }
00300
00301 }
00302
00303 typedef mesh_filter_test::MeshFilterTest<float> MeshFilterTestFloat;
00304 TEST_P(MeshFilterTestFloat, float)
00305 {
00306 this->setMeshDistance(this->GetParam());
00307 this->test();
00308 }
00309 INSTANTIATE_TEST_CASE_P(float_test, MeshFilterTestFloat, ::testing::Range<double>(0.0f, 6.0f, 0.5f));
00310
00311 typedef mesh_filter_test::MeshFilterTest<unsigned short> MeshFilterTestUnsignedShort;
00312 TEST_P(MeshFilterTestUnsignedShort, unsigned_short)
00313 {
00314 this->setMeshDistance(this->GetParam());
00315 this->test();
00316 }
00317 INSTANTIATE_TEST_CASE_P(ushort_test, MeshFilterTestUnsignedShort, ::testing::Range<double>(0.0f, 6.0f, 0.5f));
00318
00319 int main(int argc, char** argv)
00320 {
00321 testing::InitGoogleTest(&argc, argv);
00322 int arg;
00323
00324 return RUN_ALL_TESTS();
00325 }