Transformations.cpp
Go to the documentation of this file.
1 #include "../utest.h"
2 
3 using namespace std;
4 using namespace PointMatcherSupport;
5 
6 
7 static inline Eigen::Transform<NumericType, 2, Eigen::Affine> buildUpTransformation2D(const Eigen::Matrix<NumericType, 2, 1>& translation,
8  const Eigen::Rotation2D<NumericType>& rotation,
9  const NumericType scale = 1.0)
10 {
11  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation =
12  Eigen::Translation<NumericType, 2>(translation) * rotation * Eigen::Scaling(scale);
13  return transformation;
14 }
15 
16 static inline Eigen::Transform<NumericType, 3, Eigen::Affine> buildUpTransformation3D(const Eigen::Matrix<NumericType, 3, 1>& translation,
17  const Eigen::Quaternion<NumericType>& rotation,
18  const NumericType scale = 1.0)
19 {
20  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation =
21  Eigen::Translation<NumericType, 3>(translation) * Eigen::AngleAxis<NumericType>(rotation.normalized()) * Eigen::Scaling(scale);
22  return transformation;
23 }
24 
26  std::shared_ptr<PM::Transformation>& transformator,
27  const NumericType kEpsilonNumericalError = 0)
28 {
29  // Transform point cloud.
30  auto transformedCloud = cloud;
31  transformator->inPlaceCompute(transformation, transformedCloud);
32  // Assert on the result.
33  // Transformation quality. 'Who tests the unit test?'
34  EXPECT_TRUE(transformator->checkParameters(transformation));
35  // Features.
36  for (size_t i = 0; i < cloud.getNbPoints(); ++i)
37  {
38  const auto transformedFeature = transformation * cloud.features.col(i);
39  ASSERT_TRUE(transformedFeature.isApprox(transformedCloud.features.col(i), kEpsilonNumericalError));
40  }
41 
42  // Descriptors.
43  int row(0);
44  const int descCols(cloud.descriptors.cols());
45  const unsigned int nbRows = transformation.rows() - 1;
46  const unsigned int nbCols = transformation.cols() - 1;
47  const PM::TransformationParameters R(transformation.topLeftCorner(nbRows, nbCols));
48  for (size_t i = 0; i < cloud.descriptorLabels.size(); ++i)
49  {
50  const int span(cloud.descriptorLabels[i].span);
51  const std::string& name(cloud.descriptorLabels[i].text);
52  if (name == "normals" || name == "observationDirections")
53  {
54  const auto transformedDescriptor = R * cloud.descriptors.block(row, 0, span, descCols);
55  ASSERT_TRUE(transformedDescriptor.isApprox(transformedCloud.descriptors.block(row, 0, span, descCols), kEpsilonNumericalError));
56  }
57  row += span;
58  }
59  EXPECT_EQ(cloud.featureLabels, transformedCloud.featureLabels);
60  EXPECT_EQ(cloud.descriptorLabels, transformedCloud.descriptorLabels);
61  EXPECT_EQ(cloud.timeLabels, transformedCloud.timeLabels);
62  EXPECT_EQ(cloud.times, transformedCloud.times);
63 }
64 
65 //---------------------------
66 // Transformation Checker modules
67 //---------------------------
68 
69 // Utility classes
71 {
72 public:
73  std::shared_ptr<PM::TransformationChecker> transformCheck;
74 
75  // Will be called for every tests
76  virtual void SetUp()
77  {
78  icp.setDefault();
79  // Uncomment for consol outputs
80  //setLogger(PM::get().LoggerRegistrar.create("FileLogger"));
81 
82  icp.transformationCheckers.clear();
83  }
84 
85  // Will be called for every tests
86  virtual void TearDown() {}
87 
89  {
90  transformCheck = PM::get().TransformationCheckerRegistrar.create(name, params);
91 
92  icp.transformationCheckers.push_back(transformCheck);
93  }
94 };
95 
96 
97 TEST_F(TransformationCheckerTest, CounterTransformationChecker)
98 {
99  addFilter("CounterTransformationChecker", { { "maxIterationCount", toParam(20) } });
100  validate2dTransformation();
101 }
102 
103 TEST_F(TransformationCheckerTest, DifferentialTransformationChecker)
104 {
105  addFilter("DifferentialTransformationChecker",
106  { { "minDiffRotErr", toParam(0.001) }, { "minDiffTransErr", toParam(0.001) }, { "smoothLength", toParam(4) } });
107  validate2dTransformation();
108 }
109 
110 TEST_F(TransformationCheckerTest, BoundTransformationChecker)
111 {
112  // Since that transChecker is trigger when the distance is growing
113  // and that we do not expect that to happen in the test dataset, we
114  // keep the Counter to get out of the looop
115  std::shared_ptr<PM::TransformationChecker> extraTransformCheck;
116 
117  extraTransformCheck = PM::get().TransformationCheckerRegistrar.create("CounterTransformationChecker");
118  icp.transformationCheckers.push_back(extraTransformCheck);
119 
120  addFilter("BoundTransformationChecker", { { "maxRotationNorm", toParam(1.0) }, { "maxTranslationNorm", toParam(1.0) } });
121  validate2dTransformation();
122 }
123 
124 //---------------------------
125 // Transformation
126 //---------------------------
127 TEST(Transformation, RigidTransformationParameterCheck)
128 {
129  std::shared_ptr<PM::Transformation> rigidTrans;
130  rigidTrans = PM::get().REG(Transformation).create("RigidTransformation");
131 
132  //-------------------------------------
133  // Construct a 3D non-orthogonal matrix
134  PM::Matrix T_3D = PM::Matrix::Identity(4, 4);
135  //T_3D(0,0) = 2.3;
136  //T_3D(0,1) = 0.03;
137  T_3D << 0.99935116, 0.13669771, 0.03436585, 1.71138524, -0.02633967, 0.99326295, -0.04907545, -0.10860933, -0.03615132, 0.04400287,
138  0.99820427, -0.04454497, 0., 0., 0., 1.;
139 
140  EXPECT_FALSE(rigidTrans->checkParameters(T_3D));
141 
142  EXPECT_THROW(rigidTrans->compute(data3D, T_3D), TransformationError);
143 
144  // Check stability over iterations
145  for (int i = 0; i < 10; i++)
146  {
147  T_3D = rigidTrans->correctParameters(T_3D);
148  ASSERT_TRUE(rigidTrans->checkParameters(T_3D));
149  }
150 
151  //-------------------------------------
152  // Construct a 2D non-orthogonal matrix
153  PM::Matrix T_2D_non_ortho = PM::Matrix::Identity(3, 3);
154  T_2D_non_ortho(0, 0) = 0.8;
155  T_2D_non_ortho(0, 1) = -0.5;
156  T_2D_non_ortho(1, 0) = 0.5;
157  T_2D_non_ortho(1, 1) = 0.8;
158 
159  EXPECT_FALSE(rigidTrans->checkParameters(T_2D_non_ortho));
160 
161  EXPECT_THROW(rigidTrans->compute(data2D, T_2D_non_ortho), TransformationError);
162  EXPECT_THROW(rigidTrans->inPlaceCompute(T_2D_non_ortho, data2D), TransformationError);
163 
164  // Check stability over iterations
165  for (int i = 0; i < 10; i++)
166  {
167  T_2D_non_ortho = rigidTrans->correctParameters(T_2D_non_ortho);
168  EXPECT_TRUE(rigidTrans->checkParameters(T_2D_non_ortho));
169  }
170 
171  //-------------------------------------
172  // Construct a 2D reflection matrix
173  PM::Matrix T_2D_reflection = PM::Matrix::Identity(3, 3);
174  T_2D_reflection(1, 1) = -1;
175 
176  EXPECT_THROW(rigidTrans->correctParameters(T_2D_reflection), TransformationError);
177 }
178 
179 TEST(Transformation, ComputePureTranslationDataPoints2D)
180 {
181  std::shared_ptr<PM::Transformation> transformator = PM::get().REG(Transformation).create("PureTranslation");
182 
183  // Identity.
184  {
185  const Eigen::Matrix<NumericType, 2, 1> translation{ 0, 0 };
186  const Eigen::Rotation2D<NumericType> rotation{ 0 };
187  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation = buildUpTransformation2D(translation, rotation);
188  // Transform and assert on the result.
189  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
190  }
191  // Pure translation.
192  {
193  const Eigen::Matrix<NumericType, 2, 1> translation{ -1.0001, 34.5 };
194  const Eigen::Rotation2D<NumericType> rotation{ 0 };
195  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation = buildUpTransformation2D(translation, rotation);
196  // Transform and assert on the result.
197  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
198  }
199 }
200 
201 TEST(Transformation, ComputePureTranslationDataPoints3D)
202 {
203  std::shared_ptr<PM::Transformation> transformator = PM::get().REG(Transformation).create("PureTranslation");
204 
205  // Identity.
206  {
207  const Eigen::Matrix<NumericType, 3, 1> translation{ 0, 0, 0 };
208  const Eigen::Quaternion<NumericType> rotation{ 1, 0, 0, 0 };
209  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation = buildUpTransformation3D(translation, rotation);
210  // Transform and assert on the result.
211  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
212  }
213 
214  // Pure translation.
215  {
216  const Eigen::Matrix<NumericType, 3, 1> translation{ -1.0001, 5, -12321.234 };
217  const Eigen::Quaternion<NumericType> rotation{ 1, 0, 0, 0 };
218  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation = buildUpTransformation3D(translation, rotation);
219  // Transform and assert on the result.
220  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
221  }
222 }
223 
224 TEST(Transformation, ComputeRigidTransformDataPoints2D)
225 {
226  std::shared_ptr<PM::Transformation> transformator = PM::get().REG(Transformation).create("RigidTransformation");
227 
228  // Identity.
229  {
230  const Eigen::Matrix<NumericType, 2, 1> translation{ 0, 0 };
231  const Eigen::Rotation2D<NumericType> rotation{ 0 };
232  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation = buildUpTransformation2D(translation, rotation);
233  // Transform and assert on the result.
234  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
235  }
236  // Pure translation.
237  {
238  const Eigen::Matrix<NumericType, 2, 1> translation{ -1.0001, 34.5 };
239  const Eigen::Rotation2D<NumericType> rotation{ 0 };
240  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation = buildUpTransformation2D(translation, rotation);
241  // Transform and assert on the result.
242  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
243  }
244  // Pure rotation.
245  {
246  const Eigen::Matrix<NumericType, 2, 1> translation{ 0, 0 };
247  const Eigen::Rotation2D<NumericType> rotation{ 3.53453 };
248  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation = buildUpTransformation2D(translation, rotation);
249  // Transform and assert on the result.
250  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
251  }
252  // Translation + rotation.
253  {
254  const Eigen::Matrix<NumericType, 2, 1> translation{ -3.11, 100.222 };
255  const Eigen::Rotation2D<NumericType> rotation{ -123.3 };
256  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation = buildUpTransformation2D(translation, rotation);
257  // Transform and assert on the result.
258  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
259  }
260 }
261 
262 TEST(Transformation, ComputeRigidTransformDataPoints3D)
263 {
264  std::shared_ptr<PM::Transformation> transformator = PM::get().REG(Transformation).create("RigidTransformation");
265 
266  // Identity.
267  {
268  const Eigen::Matrix<NumericType, 3, 1> translation{ 0, 0, 0 };
269  const Eigen::Quaternion<NumericType> rotation{ 1, 0, 0, 0 };
270  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation = buildUpTransformation3D(translation, rotation);
271  // Transform and assert on the result.
272  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
273  }
274 
275  // Pure translation.
276  {
277  const Eigen::Matrix<NumericType, 3, 1> translation{ -1.0001, 5, -12321.234 };
278  const Eigen::Quaternion<NumericType> rotation{ 1, 0, 0, 0 };
279  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation = buildUpTransformation3D(translation, rotation);
280  // Transform and assert on the result.
281  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
282  }
283  // Pure rotation.
284  {
285  const Eigen::Matrix<NumericType, 3, 1> translation{ 0, 0, 0 };
286  const Eigen::Quaternion<NumericType> rotation{ 1, -5, 23, 0.5 };
287  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation = buildUpTransformation3D(translation, rotation);
288  // Transform and assert on the result.
289  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
290  }
291  // Translation + rotation.
292  {
293  const NumericType kEpsilonNumericalError = 1e-6;
294  const Eigen::Matrix<NumericType, 3, 1> translation{ 1, -3, -4 };
295  const Eigen::Quaternion<NumericType> rotation{ 0, -2.54, 0, 0.5 };
296  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation = buildUpTransformation3D(translation, rotation);
297  // Transform and assert on the result.
298  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator, kEpsilonNumericalError);
299  }
300 }
301 
302 TEST(Transformation, ComputeSimilarityTransformDataPoints2D)
303 {
304  std::shared_ptr<PM::Transformation> transformator = PM::get().REG(Transformation).create("SimilarityTransformation");
305 
306  // Identity.
307  {
308  const Eigen::Matrix<NumericType, 2, 1> translation{ 0, 0 };
309  const Eigen::Rotation2D<NumericType> rotation{ 0 };
310  const NumericType scale{ 1.0 };
311  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation = buildUpTransformation2D(translation, rotation, scale);
312  // Transform and assert on the result.
313  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
314  }
315  // Pure Upscaling.
316  {
317  const Eigen::Matrix<NumericType, 2, 1> translation{ 0, 0 };
318  const Eigen::Rotation2D<NumericType> rotation{ 0 };
319  const NumericType scale{ 5.0 };
320  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation = buildUpTransformation2D(translation, rotation, scale);
321  // Transform and assert on the result.
322  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
323  }
324  // Pure Downscaling.
325  {
326  const Eigen::Matrix<NumericType, 2, 1> translation{ 0, 0 };
327  const Eigen::Rotation2D<NumericType> rotation{ 0 };
328  const NumericType scale{ 0.1 };
329  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation = buildUpTransformation2D(translation, rotation, scale);
330  // Transform and assert on the result.
331  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
332  }
333  // Pure translation + Downscaling.
334  {
335  const Eigen::Matrix<NumericType, 2, 1> translation{ -1.0001, 34.5 };
336  const Eigen::Rotation2D<NumericType> rotation{ 0 };
337  const NumericType scale{ 0.5 };
338  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation = buildUpTransformation2D(translation, rotation, scale);
339  // Transform and assert on the result.
340  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
341  }
342  // Pure rotation + Upscaling.
343  {
344  const Eigen::Matrix<NumericType, 2, 1> translation{ 0, 0 };
345  const Eigen::Rotation2D<NumericType> rotation{ 3.53453 };
346  const NumericType scale{ 1.9 };
347  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation = buildUpTransformation2D(translation, rotation, scale);
348  // Transform and assert on the result.
349  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
350  }
351  // Translation + rotation + Upscaling.
352  {
353  const Eigen::Matrix<NumericType, 2, 1> translation{ -3.11, 100.222 };
354  const Eigen::Rotation2D<NumericType> rotation{ -123.3 };
355  const NumericType scale{ 1.9 };
356  const Eigen::Transform<NumericType, 2, Eigen::Affine> transformation = buildUpTransformation2D(translation, rotation, scale);
357  // Transform and assert on the result.
358  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
359  }
360 }
361 
362 TEST(Transformation, ComputeSimilarityTransformDataPoints3D)
363 {
364  std::shared_ptr<PM::Transformation> transformator = PM::get().REG(Transformation).create("SimilarityTransformation");
365 
366  // Identity.
367  {
368  const Eigen::Matrix<NumericType, 3, 1> translation{ 0, 0, 0 };
369  const Eigen::Quaternion<NumericType> rotation{ 1, 0, 0, 0 };
370  const NumericType scale{ 1.0 };
371  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation = buildUpTransformation3D(translation, rotation, scale);
372  // Transform and assert on the result.
373  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
374  }
375  // Pure Upscaling.
376  {
377  const Eigen::Matrix<NumericType, 3, 1> translation{ 0, 0, 0 };
378  const Eigen::Quaternion<NumericType> rotation{ 1, 0, 0, 0 };
379  const NumericType scale{ 5.0 };
380  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation = buildUpTransformation3D(translation, rotation, scale);
381  // Transform and assert on the result.
382  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
383  }
384  // Pure Downscaling.
385  {
386  const Eigen::Matrix<NumericType, 3, 1> translation{ 0, 0, 0 };
387  const Eigen::Quaternion<NumericType> rotation{ 1, 0, 0, 0 };
388  const NumericType scale{ 0.1 };
389  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation = buildUpTransformation3D(translation, rotation, scale);
390  // Transform and assert on the result.
391  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
392  }
393  // Pure translation + Downscaling.
394  {
395  const Eigen::Matrix<NumericType, 3, 1> translation{ -1.0001, 5, -12321.234 };
396  const Eigen::Quaternion<NumericType> rotation{ 1, 0, 0, 0 };
397  const NumericType scale{ 0.5 };
398  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation = buildUpTransformation3D(translation, rotation, scale);
399  // Transform and assert on the result.
400  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
401  }
402  // Pure rotation + Upscaling.
403  {
404  const Eigen::Matrix<NumericType, 3, 1> translation{ 0, 0, 0 };
405  const Eigen::Quaternion<NumericType> rotation{ 1, -5, 23, 0.5 };
406  const NumericType scale{ 1.9 };
407  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation = buildUpTransformation3D(translation, rotation, scale);
408  // Transform and assert on the result.
409  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator);
410  }
411  // Translation + rotation + Upscaling.
412  {
413  const NumericType kEpsilonNumericalError = 1e-6;
414  const Eigen::Matrix<NumericType, 3, 1> translation{ 1, -3, -4 };
415  const Eigen::Quaternion<NumericType> rotation{ 0, -2.54, 0, 0.5 };
416  const NumericType scale{ 1.9 };
417  const Eigen::Transform<NumericType, 3, Eigen::Affine> transformation = buildUpTransformation3D(translation, rotation, scale);
418  // Transform and assert on the result.
419  assertOnDataPointsTransformation(data3D, transformation.matrix(), transformator, kEpsilonNumericalError);
420  }
421 }
Definition: icp.py:1
TEST(Transformation, RigidTransformationParameterCheck)
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:19311
std::string toParam(const S &value)
Return the a string value using lexical_cast.
static Eigen::Transform< NumericType, 2, Eigen::Affine > buildUpTransformation2D(const Eigen::Matrix< NumericType, 2, 1 > &translation, const Eigen::Rotation2D< NumericType > &rotation, const NumericType scale=1.0)
TEST_F(TransformationCheckerTest, CounterTransformationChecker)
DP data3D
Definition: utest.cpp:48
PM::DataPoints DataPoints
::std::string string
Definition: gtest.h:1979
rotation
Definition: icp.py:74
A function that transforms points and their descriptors given a transformation matrix.
Definition: PointMatcher.h:404
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic > Matrix
A dense matrix over ScalarType.
Definition: PointMatcher.h:169
Parametrizable::Parameters Parameters
alias
Definition: PointMatcher.h:186
Functions and classes that are not dependant on scalar type are defined in this namespace.
transformation
Definition: build_map.py:37
#define ASSERT_TRUE(condition)
Definition: gtest.h:19333
DP data2D
Definition: utest.cpp:46
static const PointMatcher & get()
Return instances.
Definition: Registry.cpp:145
translation
Definition: icp.py:73
std::shared_ptr< PM::TransformationChecker > transformCheck
#define EXPECT_EQ(expected, actual)
Definition: gtest.h:19747
#define EXPECT_TRUE(condition)
Definition: gtest.h:19327
An expection thrown when a transformation has invalid parameters.
Definition: PointMatcher.h:89
static Eigen::Transform< NumericType, 3, Eigen::Affine > buildUpTransformation3D(const Eigen::Matrix< NumericType, 3, 1 > &translation, const Eigen::Quaternion< NumericType > &rotation, const NumericType scale=1.0)
#define EXPECT_FALSE(condition)
Definition: gtest.h:19330
static void assertOnDataPointsTransformation(const PM::DataPoints &cloud, const PM::TransformationParameters &transformation, std::shared_ptr< PM::Transformation > &transformator, const NumericType kEpsilonNumericalError=0)
Matrix TransformationParameters
A matrix holding the parameters a transformation.
Definition: PointMatcher.h:182
void addFilter(string name, PM::Parameters params)
float NumericType
Definition: utest.h:15


libpointmatcher
Author(s):
autogenerated on Sat May 27 2023 02:38:03