ICP.cpp
Go to the documentation of this file.
1 // ****************************************************************************
2 // This file is part of the Integrating Vision Toolkit (IVT).
3 //
4 // The IVT is maintained by the Karlsruhe Institute of Technology (KIT)
5 // (www.kit.edu) in cooperation with the company Keyetech (www.keyetech.de).
6 //
7 // Copyright (C) 2014 Karlsruhe Institute of Technology (KIT).
8 // All rights reserved.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are met:
12 //
13 // 1. Redistributions of source code must retain the above copyright
14 // notice, this list of conditions and the following disclaimer.
15 //
16 // 2. Redistributions in binary form must reproduce the above copyright
17 // notice, this list of conditions and the following disclaimer in the
18 // documentation and/or other materials provided with the distribution.
19 //
20 // 3. Neither the name of the KIT nor the names of its contributors may be
21 // used to endorse or promote products derived from this software
22 // without specific prior written permission.
23 //
24 // THIS SOFTWARE IS PROVIDED BY THE KIT AND CONTRIBUTORS “AS IS” AND ANY
25 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 // DISCLAIMED. IN NO EVENT SHALL THE KIT OR CONTRIBUTORS BE LIABLE FOR ANY
28 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 // ****************************************************************************
35 // ****************************************************************************
36 // Filename: ICP.cpp
37 // Author: Pedram Azad
38 // Date: 06.09.2003
39 // ****************************************************************************
40 
41 
42 // ****************************************************************************
43 // Includes
44 // ****************************************************************************
45 
46 #include <new> // for explicitly using correct new/delete operators on VC DSPs
47 
48 #include "ICP.h"
49 
50 #include "Math/Math3d.h"
51 
52 #include <stdio.h>
53 #include <math.h>
54 
55 
56 
57 // ****************************************************************************
58 // Defines and static functions (internal use only)
59 // ****************************************************************************
60 
61 #define JACOBI_ROTATE(a, i, j, k, l) g = a[i][j]; h = a[k][l]; a[i][j] = g - s * (h + g * tau); a[k][l] = h + s * (g - h * tau)
62 #define JACOBI_MAX_ROTATIONS 20
63 
64 static void Jacobi4(double **a, double *w, double **v)
65 {
66  int i, j, k, l;
67  double b[4], z[4];
68 
69  // initialize
70  for (i = 0; i < 4; i++)
71  {
72  for (j = 0; j < 4; j++)
73  v[i][j] = 0.0;
74 
75  v[i][i] = 1.0;
76  z[i] = 0.0;
77  b[i] = w[i] = a[i][i];
78  }
79 
80  // begin rotation sequence
81  for (i = 0; i < JACOBI_MAX_ROTATIONS; i++)
82  {
83  double sum = 0.0;
84 
85  for (j = 0; j < 3; j++)
86  {
87  for (k = j + 1; k < 4; k++)
88  sum += fabs(a[j][k]);
89  }
90 
91  if (sum == 0.0)
92  break;
93 
94  const double tresh = (i < 3) ? 0.2 * sum / 16 : 0;
95 
96  for (j = 0; j < 3; j++)
97  {
98  for (k = j + 1; k < 4; k++)
99  {
100  double g = 100.0 * fabs(a[j][k]);
101  double theta, t;
102 
103  // after for runs
104  if (i > 3 && (fabs(w[j]) + g) == fabs(w[j]) && (fabs(w[k]) + g) == fabs(w[k]))
105  {
106  a[j][k] = 0.0;
107  }
108  else if (fabs(a[j][k]) > tresh)
109  {
110  double h = w[k] - w[j];
111 
112  if ((fabs(h) + g) == fabs(h))
113  {
114  t = (a[j][k]) / h;
115  }
116  else
117  {
118  theta = 0.5 * h / a[j][k];
119  t = 1.0 / (fabs(theta) + sqrt(1.0 + theta * theta));
120 
121  if (theta < 0.0)
122  t = -t;
123  }
124 
125  double c = 1.0 / sqrt(1.0 + t * t);
126  double s = t * c;
127  double tau = s / (1.0 + c);
128  h = t * a[j][k];
129  z[j] -= h;
130  z[k] += h;
131  w[j] -= h;
132  w[k] += h;
133  a[j][k] = 0.0;
134 
135  // j already shifted left by 1 unit
136  for (l = 0; l < j; l++)
137  {
138  JACOBI_ROTATE(a, l, j, l, k);
139  }
140 
141  // j and k already shifted left by 1 unit
142  for (l = j + 1; l < k; l++)
143  {
144  JACOBI_ROTATE(a, j, l, l, k);
145  }
146 
147  // k already shifted left by 1 unit
148  for (l = k + 1; l < 4; l++)
149  {
150  JACOBI_ROTATE(a, j, l, k, l);
151  }
152 
153  for (l = 0; l < 4; l++)
154  {
155  JACOBI_ROTATE(v, l, j, l, k);
156  }
157  }
158  }
159  }
160 
161  for (j = 0; j < 4; j++)
162  {
163  b[j] += z[j];
164  w[j] = b[j];
165  z[j] = 0.0;
166  }
167  }
168 
169  // sort eigenfunctions
170  for (j = 0; j < 3; j++)
171  {
172  int k = j;
173 
174  double tmp = w[k];
175 
176  for (i = j + 1; i < 4; i++)
177  {
178  if (w[i] > tmp)
179  {
180  k = i;
181  tmp = w[k];
182  }
183  }
184 
185  if (k != j)
186  {
187  w[k] = w[j];
188  w[j] = tmp;
189 
190  for (i = 0; i < 4; i++)
191  {
192  tmp = v[i][j];
193  v[i][j] = v[i][k];
194  v[i][k] = tmp;
195  }
196  }
197  }
198 
199  // Ensure eigenvector consistency (Jacobi can compute vectors that
200  // are negative of one another). Compute most positive eigenvector.
201  const int nCeilHalf = (4 >> 1) + (4 & 1);
202 
203  for (j = 0; j < 4; j++)
204  {
205  double sum = 0;
206 
207  for (i = 0; i < 4; i++)
208  {
209  if (v[i][j] >= 0.0)
210  sum++;
211  }
212 
213  if (sum < nCeilHalf)
214  {
215  for(i = 0; i < 4; i++)
216  v[i][j] *= -1.0;
217  }
218  }
219 }
220 
221 #undef JACOBI_ROTATE
222 #undef JACOBI_MAX_ROTATIONS
223 
224 
225 static void Perpendiculars(const double x[3], double y[3], double z[3], double theta)
226 {
227  const double x2 = x[0] * x[0];
228  const double y2 = x[1] * x[1];
229  const double z2 = x[2] * x[2];
230  const double r = sqrt(x2 + y2 + z2);
231  int dx, dy, dz;
232 
233  // transpose the vector to avoid division-by-zero
234  if (x2 > y2 && x2 > z2)
235  {
236  dx = 0;
237  dy = 1;
238  dz = 2;
239  }
240  else if (y2 > z2)
241  {
242  dx = 1;
243  dy = 2;
244  dz = 0;
245  }
246  else
247  {
248  dx = 2;
249  dy = 0;
250  dz = 1;
251  }
252 
253  const double a = x[dx] / r;
254  const double b = x[dy] / r;
255  const double c = x[dz] / r;
256  const double tmp = sqrt(a * a + c * c);
257 
258  if (theta != 0)
259  {
260  const double sintheta = sin(theta);
261  const double costheta = cos(theta);
262 
263  if (y)
264  {
265  y[dx] = (c * costheta - a * b * sintheta) / tmp;
266  y[dy] = sintheta * tmp;
267  y[dz] = (- a * costheta - b * c * sintheta) / tmp;
268  }
269 
270  if (z)
271  {
272  z[dx] = (-c * sintheta - a * b * costheta) / tmp;
273  z[dy] = costheta * tmp;
274  z[dz] = (a * sintheta - b * c * costheta) / tmp;
275  }
276  }
277  else
278  {
279  if (y)
280  {
281  y[dx] = c / tmp;
282  y[dy] = 0;
283  y[dz] = - a / tmp;
284  }
285 
286  if (z)
287  {
288  z[dx] = - a * b / tmp;
289  z[dy] = tmp;
290  z[dz] = - b * c / tmp;
291  }
292  }
293 }
294 
295 
296 // ****************************************************************************
297 // Methods
298 // ****************************************************************************
299 
300 bool CICP::CalculateOptimalTransformation(const Vec3d *pSourcePoints, const Vec3d *pTargetPoints, int nPoints, Mat3d &rotation, Vec3d &translation)
301 {
302  if (nPoints < 2)
303  {
304  printf("error: CICP::CalculateOptimalTransformation needs at least two point pairs");
305  Math3d::SetMat(rotation, Math3d::unit_mat);
306  Math3d::SetVec(translation, Math3d::zero_vec);
307  return false;
308  }
309 
310  // The solution is based on
311  // Berthold K. P. Horn (1987),
312  // "Closed-form solution of absolute orientation using unit quaternions,"
313  // Journal of the Optical Society of America A, pp. 629-642
314  // Original python implementation by David G. Gobbi.
315 
316  // find the centroid of each set
317  Vec3d source_centroid = { 0.0f, 0.0f, 0.0f };
318  Vec3d target_centroid = { 0.0f, 0.0f, 0.0f };
319 
320  int i;
321 
322  for (i = 0; i < nPoints; i++)
323  {
324  Math3d::AddToVec(source_centroid, pSourcePoints[i]);
325  Math3d::AddToVec(target_centroid, pTargetPoints[i]);
326  }
327 
328  Math3d::MulVecScalar(source_centroid, 1.0f / nPoints, source_centroid);
329  Math3d::MulVecScalar(target_centroid, 1.0f / nPoints, target_centroid);
330 
331  // build the 3x3 matrix M
332  Mat3d M = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
333 
334  for (i = 0; i < nPoints; i++)
335  {
336  Vec3d a, b;
337  Mat3d matrix;
338 
339  Math3d::SubtractVecVec(pSourcePoints[i], source_centroid, a);
340  Math3d::SubtractVecVec(pTargetPoints[i], target_centroid, b);
341 
342  // accumulate the products a * b^T into the matrix M
343  Math3d::MulVecTransposedVec(a, b, matrix);
344  Math3d::AddToMat(M, matrix);
345  }
346 
347  // build the 4x4 matrix N
348  double N0[4], N1[4], N2[4], N3[4];
349  double *N[4] = { N0, N1, N2, N3 };
350 
351  for (i = 0; i < 4; i++)
352  {
353  // fill N with zeros
354  N[i][0] = 0.0f;
355  N[i][1] = 0.0f;
356  N[i][2] = 0.0f;
357  N[i][3] = 0.0f;
358  }
359 
360  // on-diagonal elements
361  N[0][0] = M.r1 + M.r5 + M.r9;
362  N[1][1] = M.r1 - M.r5 - M.r9;
363  N[2][2] = -M.r1 + M.r5 - M.r9;
364  N[3][3] = -M.r1 - M.r5 + M.r9;
365 
366  // off-diagonal elements
367  N[0][1] = N[1][0] = M.r6 - M.r8;
368  N[0][2] = N[2][0] = M.r7 - M.r3;
369  N[0][3] = N[3][0] = M.r2 - M.r4;
370 
371  N[1][2] = N[2][1] = M.r2 + M.r4;
372  N[1][3] = N[3][1] = M.r7 + M.r3;
373  N[2][3] = N[3][2] = M.r6 + M.r8;
374 
375  double eigenvalues[4];
376  double eigenvectors0[4], eigenvectors1[4], eigenvectors2[4], eigenvectors3[4];
377  double *eigenvectors[4] = { eigenvectors0, eigenvectors1, eigenvectors2, eigenvectors3 };
378 
379  // eigen-decompose N (is symmetric)
380  Jacobi4(N, eigenvalues, eigenvectors);
381 
382  // the eigenvector with the largest eigenvalue is the quaternion we want
383  // (they are sorted in decreasing order for us by JacobiN)
384  float w, x, y, z;
385 
386  // first: if points are collinear, choose the quaternion that
387  // results in the smallest rotation.
388  if (eigenvalues[0] == eigenvalues[1] || nPoints == 2)
389  {
390  Vec3d s0, t0, s1, t1;
391  Math3d::SetVec(s0, pSourcePoints[0]);
392  Math3d::SetVec(t0, pTargetPoints[0]);
393  Math3d::SetVec(s1, pSourcePoints[1]);
394  Math3d::SetVec(t1, pTargetPoints[1]);
395 
396  Vec3d ds, dt;
397  Math3d::SubtractVecVec(s1, s0, ds);
398  Math3d::SubtractVecVec(t1, t0, dt);
401 
402  // take dot & cross product
403  w = ds.x * dt.x + ds.y * dt.y + ds.z * dt.z;
404  x = ds.y * dt.z - ds.z * dt.y;
405  y = ds.z * dt.x - ds.x * dt.z;
406  z = ds.x * dt.y - ds.y * dt.x;
407 
408  float r = sqrtf(x * x + y * y + z * z);
409  const float theta = atan2f(r, w);
410 
411  // construct quaternion
412  w = cosf(0.5f * theta);
413 
414  if (r != 0)
415  {
416  r = sinf(0.5f * theta) / r;
417  x = x * r;
418  y = y * r;
419  z = z * r;
420  }
421  else // rotation by 180 degrees: special case
422  {
423  // rotate around a vector perpendicular to ds
424  double ds_[3] = { ds.x, ds.y, ds.z };
425  double dt_[3];
426 
427  Perpendiculars(ds_, dt_, 0, 0);
428 
429  r = sinf(0.5f * theta);
430  x = float(dt_[0] * r);
431  y = float(dt_[1] * r);
432  z = float(dt_[2] * r);
433  }
434  }
435  else
436  {
437  // points are not collinear
438  w = (float) eigenvectors[0][0];
439  x = (float) eigenvectors[1][0];
440  y = (float) eigenvectors[2][0];
441  z = (float) eigenvectors[3][0];
442  }
443 
444  // convert quaternion to a rotation matrix
445  const float ww = w * w;
446  const float wx = w * x;
447  const float wy = w * y;
448  const float wz = w * z;
449 
450  const float xx = x * x;
451  const float yy = y * y;
452  const float zz = z * z;
453 
454  const float xy = x * y;
455  const float xz = x * z;
456  const float yz = y * z;
457 
458  rotation.r1 = ww + xx - yy - zz;
459  rotation.r4 = 2.0f * (wz + xy);
460  rotation.r7 = 2.0f * (-wy + xz);
461 
462  rotation.r2 = 2.0f * (-wz + xy);
463  rotation.r5 = ww - xx + yy - zz;
464  rotation.r8 = 2.0f * (wx + yz);
465 
466  rotation.r3 = 2.0f * (wy + xz);
467  rotation.r6 = 2.0f * (-wx + yz);
468  rotation.r9 = ww - xx - yy + zz;
469 
470  // the translation is given by the difference of the transformed
471  // source centroid and the target centroid
472  Vec3d temp;
473  Math3d::MulMatVec(rotation, source_centroid, temp);
474  Math3d::SubtractVecVec(target_centroid, temp, translation);
475 
476  return true;
477 }
void MulVecTransposedVec(const Vec3d &vector1, const Vec3d &vector2, Mat3d &result)
Definition: Math3d.cpp:467
float r4
Definition: Math3d.h:95
static void Perpendiculars(const double x[3], double y[3], double z[3], double theta)
Definition: ICP.cpp:225
GLubyte g
Definition: glext.h:5166
GLdouble GLdouble t
Definition: glext.h:3219
float r7
Definition: Math3d.h:95
GLdouble GLdouble z
Definition: glext.h:3343
GLuint GLenum matrix
Definition: glext.h:5683
void AddToMat(Mat3d &matrix, const Mat3d &matrixToAdd)
Definition: Math3d.cpp:695
float r1
Definition: Math3d.h:95
float r2
Definition: Math3d.h:95
float r3
Definition: Math3d.h:95
Data structure for the representation of a 3D vector.
Definition: Math3d.h:73
float x
Definition: Math3d.h:75
GLdouble s
Definition: glext.h:3211
float z
Definition: Math3d.h:75
GLenum GLint x
Definition: glext.h:3125
const GLubyte * c
Definition: glext.h:5181
static void Jacobi4(double **a, double *w, double **v)
Definition: ICP.cpp:64
#define JACOBI_MAX_ROTATIONS
Definition: ICP.cpp:62
const Vec3d zero_vec
Definition: Math3d.cpp:59
void SetVec(Vec3d &vec, float x, float y, float z)
Definition: Math3d.cpp:243
float y
Definition: Math3d.h:75
float r6
Definition: Math3d.h:95
void MulVecScalar(const Vec3d &vec, float scalar, Vec3d &result)
Definition: Math3d.cpp:502
void AddToVec(Vec3d &vec, const Vec3d &vectorToAdd)
Definition: Math3d.cpp:481
static bool CalculateOptimalTransformation(const Vec3d *pSourcePoints, const Vec3d *pTargetPoints, int nPoints, Mat3d &rotation, Vec3d &translation)
Definition: ICP.cpp:300
void MulMatVec(const Mat3d &matrix, const Vec3d &vec, Vec3d &result)
Definition: Math3d.cpp:422
#define JACOBI_ROTATE(a, i, j, k, l)
Definition: ICP.cpp:61
float r8
Definition: Math3d.h:95
float r9
Definition: Math3d.h:95
GLubyte GLubyte GLubyte a
Definition: glext.h:5166
GLubyte GLubyte b
Definition: glext.h:5166
GLdouble GLdouble GLdouble r
Definition: glext.h:3227
void NormalizeVec(Vec3d &vec)
Definition: Math3d.cpp:573
float r5
Definition: Math3d.h:95
const Mat3d unit_mat
Definition: Math3d.cpp:60
GLenum GLint GLint y
Definition: glext.h:3125
const GLdouble * v
Definition: glext.h:3212
void SubtractVecVec(const Vec3d &vector1, const Vec3d &vector2, Vec3d &result)
Definition: Math3d.cpp:522
void SetMat(Mat3d &matrix, float r1, float r2, float r3, float r4, float r5, float r6, float r7, float r8, float r9)
Definition: Math3d.cpp:257
Data structure for the representation of a 3x3 matrix.
Definition: Math3d.h:93
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3571


asr_ivt
Author(s): Allgeyer Tobias, Hutmacher Robin, Kleinert Daniel, Meißner Pascal, Scholz Jonas, Stöckle Patrick
autogenerated on Mon Dec 2 2019 03:47:28