Main MRPT website > C++ reference for MRPT 1.9.9
se3_l2.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "tfest-precomp.h" // Precompiled headers
11 
12 #include <mrpt/tfest/se3.h>
13 #include <mrpt/poses/CPose3D.h>
14 #include <mrpt/poses/CPose3DQuat.h>
15 
16 using namespace mrpt;
17 using namespace mrpt::tfest;
18 using namespace mrpt::utils;
19 using namespace mrpt::poses;
20 using namespace mrpt::math;
21 using namespace std;
22 
23 // "Closed-form solution of absolute orientation using unit quaternions", BKP
24 // Horn, Journal of the Optical Society of America, 1987.
25 // Algorithm:
26 // 0. Preliminary
27 // pLi = { pLix, pLiy, pLiz }
28 // pRi = { pRix, pRiy, pRiz }
29 // -------------------------------------------------------
30 // 1. Find the centroids of the two sets of measurements:
31 // ct_others = (1/n)*sum{i}( pLi ) ct_others = { cLx, cLy, cLz }
32 // ct_this = (1/n)*sum{i}( pRi ) ct_this = { cRx, cRy, cRz }
33 //
34 // 2. Substract centroids from the point coordinates:
35 // pLi' = pLi - ct_others pLi' = { pLix', pLiy', pLiz' }
36 // pRi' = pRi - ct_this pRi' = { pRix', pRiy', pRiz' }
37 //
38 // 3. For each pair of coordinates (correspondences) compute the nine possible
39 // products:
40 // pi1 = pLix'*pRix' pi2 = pLix'*pRiy' pi3 = pLix'*pRiz'
41 // pi4 = pLiy'*pRix' pi5 = pLiy'*pRiy' pi6 = pLiy'*pRiz'
42 // pi7 = pLiz'*pRix' pi8 = pLiz'*pRiy' pi9 = pLiz'*pRiz'
43 //
44 // 4. Compute S components:
45 // Sxx = sum{i}( pi1 ) Sxy = sum{i}( pi2 ) Sxz = sum{i}( pi3 )
46 // Syx = sum{i}( pi4 ) Syy = sum{i}( pi5 ) Syz = sum{i}( pi6 )
47 // Szx = sum{i}( pi7 ) Szy = sum{i}( pi8 ) Szz = sum{i}( pi9 )
48 //
49 // 5. Compute N components:
50 // [ Sxx+Syy+Szz Syz-Szy Szx-Sxz Sxy-Syx ]
51 // [ Syz-Szy Sxx-Syy-Szz Sxy+Syx Szx+Sxz ]
52 // N = [ Szx-Sxz Sxy+Syx -Sxx+Syy-Szz Syz+Szy ]
53 // [ Sxy-Syx Szx+Sxz Syz+Szy -Sxx-Syy+Szz ]
54 //
55 // 6. Rotation represented by the quaternion eigenvector correspondent to the
56 // higher eigenvalue of N
57 //
58 // 7. Scale computation (symmetric expression)
59 // s = sqrt( sum{i}( square(abs(pRi')) / sum{i}( square(abs(pLi')) ) )
60 //
61 // 8. Translation computation (distance between the Right centroid and the
62 // scaled and rotated Left centroid)
63 // t = ct_this-sR(ct_others)
64 
65 /*---------------------------------------------------------------
66  se3_l2 (old "HornMethod()")
67  ---------------------------------------------------------------*/
69  std::vector<mrpt::math::TPoint3D>&
70  points_this, // IN/OUT: It gets modified!
71  std::vector<mrpt::math::TPoint3D>&
72  points_other, // IN/OUT: It gets modified!
73  mrpt::poses::CPose3DQuat& out_transform,
74  double& out_scale, bool forceScaleToUnity)
75 {
77 
78  ASSERT_EQUAL_(points_this.size(), points_other.size())
79 
80  // Compute the centroids
81  TPoint3D ct_others(0, 0, 0), ct_this(0, 0, 0);
82  const size_t nMatches = points_this.size();
83 
84  if (nMatches < 3)
85  return false; // Nothing we can estimate without 3 points!!
86 
87  for (size_t i = 0; i < nMatches; i++)
88  {
89  ct_others += points_other[i];
90  ct_this += points_this[i];
91  }
92 
93  const double F = 1.0 / nMatches;
94  ct_others *= F;
95  ct_this *= F;
96 
97  CMatrixDouble33 S; // Zeroed by default
98 
99  // Substract the centroid and compute the S matrix of cross products
100  for (size_t i = 0; i < nMatches; i++)
101  {
102  points_this[i] -= ct_this;
103  points_other[i] -= ct_others;
104 
105  S.get_unsafe(0, 0) += points_other[i].x * points_this[i].x;
106  S.get_unsafe(0, 1) += points_other[i].x * points_this[i].y;
107  S.get_unsafe(0, 2) += points_other[i].x * points_this[i].z;
108 
109  S.get_unsafe(1, 0) += points_other[i].y * points_this[i].x;
110  S.get_unsafe(1, 1) += points_other[i].y * points_this[i].y;
111  S.get_unsafe(1, 2) += points_other[i].y * points_this[i].z;
112 
113  S.get_unsafe(2, 0) += points_other[i].z * points_this[i].x;
114  S.get_unsafe(2, 1) += points_other[i].z * points_this[i].y;
115  S.get_unsafe(2, 2) += points_other[i].z * points_this[i].z;
116  }
117 
118  // Construct the N matrix
119  CMatrixDouble44 N; // Zeroed by default
120 
121  N.set_unsafe(
122  0, 0, S.get_unsafe(0, 0) + S.get_unsafe(1, 1) + S.get_unsafe(2, 2));
123  N.set_unsafe(0, 1, S.get_unsafe(1, 2) - S.get_unsafe(2, 1));
124  N.set_unsafe(0, 2, S.get_unsafe(2, 0) - S.get_unsafe(0, 2));
125  N.set_unsafe(0, 3, S.get_unsafe(0, 1) - S.get_unsafe(1, 0));
126 
127  N.set_unsafe(1, 0, N.get_unsafe(0, 1));
128  N.set_unsafe(
129  1, 1, S.get_unsafe(0, 0) - S.get_unsafe(1, 1) - S.get_unsafe(2, 2));
130  N.set_unsafe(1, 2, S.get_unsafe(0, 1) + S.get_unsafe(1, 0));
131  N.set_unsafe(1, 3, S.get_unsafe(2, 0) + S.get_unsafe(0, 2));
132 
133  N.set_unsafe(2, 0, N.get_unsafe(0, 2));
134  N.set_unsafe(2, 1, N.get_unsafe(1, 2));
135  N.set_unsafe(
136  2, 2, -S.get_unsafe(0, 0) + S.get_unsafe(1, 1) - S.get_unsafe(2, 2));
137  N.set_unsafe(2, 3, S.get_unsafe(1, 2) + S.get_unsafe(2, 1));
138 
139  N.set_unsafe(3, 0, N.get_unsafe(0, 3));
140  N.set_unsafe(3, 1, N.get_unsafe(1, 3));
141  N.set_unsafe(3, 2, N.get_unsafe(2, 3));
142  N.set_unsafe(
143  3, 3, -S.get_unsafe(0, 0) - S.get_unsafe(1, 1) + S.get_unsafe(2, 2));
144 
145  // q is the quaternion correspondent to the greatest eigenvector of the N
146  // matrix (last column in Z)
147  CMatrixDouble44 Z, D;
148  vector<double> v;
149 
150  N.eigenVectors(Z, D);
151  Z.extractCol(Z.getColCount() - 1, v);
152 
153  ASSERTDEB_(
154  fabs(
155  sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]) - 1.0) <
156  0.1);
157 
158  // Make q_r > 0
159  if (v[0] < 0)
160  {
161  v[0] *= -1;
162  v[1] *= -1;
163  v[2] *= -1;
164  v[3] *= -1;
165  }
166 
167  // out_transform: Create a pose rotation with the quaternion
168  for (unsigned int i = 0; i < 4; i++) // insert the quaternion part
169  out_transform[i + 3] = v[i];
170 
171  // Compute scale
172  double s;
173  if (forceScaleToUnity)
174  {
175  s = 1.0; // Enforce scale to be 1
176  }
177  else
178  {
179  double num = 0.0;
180  double den = 0.0;
181  for (size_t i = 0; i < nMatches; i++)
182  {
183  num += square(points_other[i].x) + square(points_other[i].y) +
184  square(points_other[i].z);
185  den += square(points_this[i].x) + square(points_this[i].y) +
186  square(points_this[i].z);
187  } // end-for
188 
189  // The scale:
190  s = std::sqrt(num / den);
191  }
192 
193  TPoint3D pp;
194  out_transform.composePoint(
195  ct_others.x, ct_others.y, ct_others.z, pp.x, pp.y, pp.z);
196  pp *= s;
197 
198  out_transform[0] = ct_this.x - pp.x; // X
199  out_transform[1] = ct_this.y - pp.y; // Y
200  out_transform[2] = ct_this.z - pp.z; // Z
201 
202  out_scale = s; // return scale
203  return true;
204 
205  MRPT_END
206 } // end se3_l2_internal()
207 
209  const std::vector<mrpt::math::TPoint3D>& in_points_this,
210  const std::vector<mrpt::math::TPoint3D>& in_points_other,
211  mrpt::poses::CPose3DQuat& out_transform, double& out_scale,
212  bool forceScaleToUnity)
213 {
214  // make a copy because we need it anyway to substract the centroid and to
215  // provide a unified interface to TMatchingList API
216  std::vector<mrpt::math::TPoint3D> points_this = in_points_this;
217  std::vector<mrpt::math::TPoint3D> points_other = in_points_other;
218 
219  return se3_l2_internal(
220  points_this, points_other, out_transform, out_scale, forceScaleToUnity);
221 }
222 
224  const mrpt::utils::TMatchingPairList& corrs,
225  mrpt::poses::CPose3DQuat& out_transform, double& out_scale,
226  bool forceScaleToUnity)
227 {
228  // Transform data types:
229  const size_t N = corrs.size();
230  std::vector<mrpt::math::TPoint3D> points_this(N), points_other(N);
231  for (size_t i = 0; i < N; i++)
232  {
233  points_this[i].x = corrs[i].this_x;
234  points_this[i].y = corrs[i].this_y;
235  points_this[i].z = corrs[i].this_z;
236  points_other[i].x = corrs[i].other_x;
237  points_other[i].y = corrs[i].other_y;
238  points_other[i].z = corrs[i].other_z;
239  }
240  return se3_l2_internal(
241  points_this, points_other, out_transform, out_scale, forceScaleToUnity);
242 }
#define ASSERT_EQUAL_(__A, __B)
double x() const
Common members of all points & poses classes.
Definition: CPoseOrPoint.h:135
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
GLdouble GLdouble z
Definition: glext.h:3872
STL namespace.
GLdouble s
Definition: glext.h:3676
GLuint GLuint num
Definition: glext.h:7278
T square(const T x)
Inline function for the square of a number.
Definition: bits.h:55
void composePoint(const double lx, const double ly, const double lz, double &gx, double &gy, double &gz, mrpt::math::CMatrixFixedNumeric< double, 3, 3 > *out_jacobian_df_dpoint=nullptr, mrpt::math::CMatrixFixedNumeric< double, 3, 7 > *out_jacobian_df_dpose=nullptr) const
Computes the 3D point G such as .
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
#define MRPT_END
bool se3_l2_internal(std::vector< mrpt::math::TPoint3D > &points_this, std::vector< mrpt::math::TPoint3D > &points_other, mrpt::poses::CPose3DQuat &out_transform, double &out_scale, bool forceScaleToUnity)
Definition: se3_l2.cpp:68
A list of TMatchingPair.
Definition: TMatchingPair.h:93
bool se3_l2(const mrpt::utils::TMatchingPairList &in_correspondences, mrpt::poses::CPose3DQuat &out_transform, double &out_scale, bool forceScaleToUnity=false)
Least-squares (L2 norm) solution to finding the optimal SE(3) transform between two reference frames ...
Definition: se3_l2.cpp:223
double x
X,Y,Z coordinates.
A class used to store a 3D pose as a translation (x,y,z) and a quaternion (qr,qx,qy,qz).
Definition: CPose3DQuat.h:48
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Definition: CPoint.h:17
#define MRPT_START
const GLdouble * v
Definition: glext.h:3678
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
#define ASSERTDEB_(f)
Defines an assertion mechanism - only when compiled in debug.
GLenum GLint GLint y
Definition: glext.h:3538
GLenum GLint x
Definition: glext.h:3538
Lightweight 3D point.
Functions for estimating the optimal transformation between two frames of references given measuremen...



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019