ICP.cpp
Go to the documentation of this file.
00001 // ****************************************************************************
00002 // This file is part of the Integrating Vision Toolkit (IVT).
00003 //
00004 // The IVT is maintained by the Karlsruhe Institute of Technology (KIT)
00005 // (www.kit.edu) in cooperation with the company Keyetech (www.keyetech.de).
00006 //
00007 // Copyright (C) 2014 Karlsruhe Institute of Technology (KIT).
00008 // All rights reserved.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are met:
00012 //
00013 // 1. Redistributions of source code must retain the above copyright
00014 //    notice, this list of conditions and the following disclaimer.
00015 //
00016 // 2. Redistributions in binary form must reproduce the above copyright
00017 //    notice, this list of conditions and the following disclaimer in the
00018 //    documentation and/or other materials provided with the distribution.
00019 //
00020 // 3. Neither the name of the KIT nor the names of its contributors may be
00021 //    used to endorse or promote products derived from this software
00022 //    without specific prior written permission.
00023 //
00024 // THIS SOFTWARE IS PROVIDED BY THE KIT AND CONTRIBUTORS “AS IS” AND ANY
00025 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00026 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027 // DISCLAIMED. IN NO EVENT SHALL THE KIT OR CONTRIBUTORS BE LIABLE FOR ANY
00028 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00031 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00033 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 // ****************************************************************************
00035 // ****************************************************************************
00036 // Filename:  ICP.cpp
00037 // Author:    Pedram Azad
00038 // Date:      06.09.2003
00039 // ****************************************************************************
00040 
00041 
00042 // ****************************************************************************
00043 // Includes
00044 // ****************************************************************************
00045 
00046 #include <new> // for explicitly using correct new/delete operators on VC DSPs
00047 
00048 #include "ICP.h"
00049 
00050 #include "Math/Math3d.h"
00051 
00052 #include <stdio.h>
00053 #include <math.h>
00054 
00055 
00056 
00057 // ****************************************************************************
00058 // Defines and static functions (internal use only)
00059 // ****************************************************************************
00060 
00061 #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)
00062 #define JACOBI_MAX_ROTATIONS            20
00063 
00064 static void Jacobi4(double **a, double *w, double **v)
00065 {
00066         int i, j, k, l;
00067         double b[4], z[4];
00068 
00069         // initialize
00070         for (i = 0; i < 4; i++) 
00071         {
00072                 for (j = 0; j < 4; j++)
00073                         v[i][j] = 0.0;
00074 
00075                 v[i][i] = 1.0;
00076                 z[i] = 0.0;
00077                 b[i] = w[i] = a[i][i];
00078         }
00079   
00080         // begin rotation sequence
00081         for (i = 0; i < JACOBI_MAX_ROTATIONS; i++) 
00082         {
00083                 double sum = 0.0;
00084                 
00085                 for (j = 0; j < 3; j++) 
00086                 {
00087                         for (k = j + 1; k < 4; k++)
00088                                 sum += fabs(a[j][k]);
00089                 }
00090     
00091                 if (sum == 0.0)
00092                         break;
00093 
00094                 const double tresh = (i < 3) ? 0.2 * sum / 16 : 0;
00095 
00096                 for (j = 0; j < 3; j++)
00097                 {
00098                         for (k = j + 1; k < 4; k++) 
00099                         {
00100                                 double g = 100.0 * fabs(a[j][k]);
00101                                 double theta, t;
00102 
00103                                 // after for runs
00104                                 if (i > 3 && (fabs(w[j]) + g) == fabs(w[j]) && (fabs(w[k]) + g) == fabs(w[k]))
00105                                 {
00106                                         a[j][k] = 0.0;
00107                                 }
00108                                 else if (fabs(a[j][k]) > tresh) 
00109                                 {
00110                                         double h = w[k] - w[j];
00111                                         
00112                                         if ((fabs(h) + g) == fabs(h))
00113                                         {
00114                                                 t = (a[j][k]) / h;
00115                                         }
00116                                         else 
00117                                         {
00118                                                 theta = 0.5 * h / a[j][k];
00119                                                 t = 1.0 / (fabs(theta) + sqrt(1.0 + theta * theta));
00120             
00121                                                 if (theta < 0.0)
00122                                                         t = -t;
00123                                         }
00124 
00125                                         double c = 1.0 / sqrt(1.0 + t * t);
00126                                         double s = t * c;
00127                                         double tau = s / (1.0 + c);
00128                                         h = t * a[j][k];
00129                                         z[j] -= h;
00130                                         z[k] += h;
00131                                         w[j] -= h;
00132                                         w[k] += h;
00133                                         a[j][k] = 0.0;
00134 
00135                                         // j already shifted left by 1 unit
00136                                         for (l = 0; l < j; l++) 
00137                                         {
00138                                                 JACOBI_ROTATE(a, l, j, l, k);
00139                                         }
00140           
00141                                         // j and k already shifted left by 1 unit
00142                                         for (l = j + 1; l < k; l++) 
00143                                         {
00144                                                 JACOBI_ROTATE(a, j, l, l, k);
00145                                         }
00146           
00147                                         // k already shifted left by 1 unit
00148                                         for (l = k + 1; l < 4; l++) 
00149                                         {
00150                                                 JACOBI_ROTATE(a, j, l, k, l);
00151                                         }
00152                         
00153                                         for (l = 0; l < 4; l++) 
00154                                         {
00155                                                 JACOBI_ROTATE(v, l, j, l, k);
00156                                         }
00157                                 }
00158                         }
00159                 }
00160 
00161                 for (j = 0; j < 4; j++)
00162                 {
00163                         b[j] += z[j];
00164                         w[j] = b[j];
00165                         z[j] = 0.0;
00166                 }
00167         }
00168 
00169         // sort eigenfunctions
00170         for (j = 0; j < 3; j++)
00171         {
00172                 int k = j;
00173                 
00174                 double tmp = w[k];
00175     
00176                 for (i = j + 1; i < 4; i++)
00177                 {
00178                         if (w[i] > tmp)
00179                         {
00180                                 k = i;
00181                                 tmp = w[k];
00182                         }
00183                 }
00184     
00185                 if (k != j) 
00186                 {
00187                         w[k] = w[j];
00188                         w[j] = tmp;
00189                 
00190                         for (i = 0; i < 4; i++) 
00191                         {
00192                                 tmp = v[i][j];
00193                                 v[i][j] = v[i][k];
00194                                 v[i][k] = tmp;
00195                         }
00196                 }
00197         }
00198 
00199         // Ensure eigenvector consistency (Jacobi can compute vectors that
00200         // are negative of one another). Compute most positive eigenvector.
00201         const int nCeilHalf = (4 >> 1) + (4 & 1);
00202 
00203         for (j = 0; j < 4; j++)
00204         {
00205                 double sum = 0;
00206 
00207                 for (i = 0; i < 4; i++)
00208                 {
00209                         if (v[i][j] >= 0.0)
00210                                 sum++;
00211                 }
00212 
00213                 if (sum < nCeilHalf)
00214                 {
00215                         for(i = 0; i < 4; i++)
00216                                 v[i][j] *= -1.0;
00217                 }
00218         }
00219 }
00220 
00221 #undef JACOBI_ROTATE
00222 #undef JACOBI_MAX_ROTATIONS
00223 
00224 
00225 static void Perpendiculars(const double x[3], double y[3], double z[3], double theta)
00226 {
00227         const double x2 = x[0] * x[0];
00228         const double y2 = x[1] * x[1];
00229         const double z2 = x[2] * x[2];
00230         const double r = sqrt(x2 + y2 + z2);
00231         int dx, dy,     dz;
00232 
00233         // transpose the vector to avoid division-by-zero
00234         if (x2 > y2 && x2 > z2)
00235         {
00236                 dx = 0;
00237                 dy = 1;
00238                 dz = 2;
00239         }
00240         else if (y2 > z2) 
00241         {
00242                 dx = 1;
00243                 dy = 2;
00244                 dz = 0;
00245         }
00246         else 
00247         {
00248                 dx = 2;
00249                 dy = 0;
00250                 dz = 1;
00251         }
00252 
00253         const double a = x[dx] / r;
00254         const double b = x[dy] / r;
00255         const double c = x[dz] / r;
00256         const double tmp = sqrt(a * a + c * c);
00257 
00258         if (theta != 0)
00259     {
00260                 const double sintheta = sin(theta);
00261                 const double costheta = cos(theta);
00262 
00263                 if (y)
00264                 {
00265                         y[dx] = (c * costheta - a * b * sintheta) / tmp;
00266                         y[dy] = sintheta * tmp;
00267                         y[dz] = (- a * costheta - b * c * sintheta) / tmp;
00268                 }
00269 
00270                 if (z)
00271                 {
00272                         z[dx] = (-c * sintheta - a * b * costheta) / tmp;
00273                         z[dy] = costheta * tmp;
00274                         z[dz] = (a * sintheta - b * c * costheta) / tmp;
00275                 }
00276         }
00277         else
00278         {
00279                 if (y)
00280                 {
00281                         y[dx] = c / tmp;
00282                         y[dy] = 0;
00283                         y[dz] = - a / tmp;
00284                 }
00285 
00286                 if (z)
00287                 {
00288                         z[dx] = - a * b / tmp;
00289                         z[dy] = tmp;
00290                         z[dz] = - b * c / tmp;
00291                 }
00292         }      
00293 }
00294 
00295 
00296 // ****************************************************************************
00297 // Methods
00298 // ****************************************************************************
00299 
00300 bool CICP::CalculateOptimalTransformation(const Vec3d *pSourcePoints, const Vec3d *pTargetPoints, int nPoints, Mat3d &rotation, Vec3d &translation)
00301 {
00302         if (nPoints < 2)
00303         {
00304                 printf("error: CICP::CalculateOptimalTransformation needs at least two point pairs");
00305                 Math3d::SetMat(rotation, Math3d::unit_mat);
00306                 Math3d::SetVec(translation, Math3d::zero_vec);
00307                 return false;
00308         }
00309 
00310         // The solution is based on
00311         // Berthold K. P. Horn (1987),
00312         // "Closed-form solution of absolute orientation using unit quaternions,"
00313         // Journal of the Optical Society of America A, pp. 629-642
00314         // Original python implementation by David G. Gobbi.
00315         
00316         // find the centroid of each set
00317         Vec3d source_centroid = { 0.0f, 0.0f, 0.0f };
00318         Vec3d target_centroid = { 0.0f, 0.0f, 0.0f };
00319         
00320         int i;
00321   
00322         for (i = 0; i < nPoints; i++)
00323         {
00324                 Math3d::AddToVec(source_centroid, pSourcePoints[i]);
00325                 Math3d::AddToVec(target_centroid, pTargetPoints[i]);
00326         }
00327 
00328         Math3d::MulVecScalar(source_centroid, 1.0f / nPoints, source_centroid);
00329         Math3d::MulVecScalar(target_centroid, 1.0f / nPoints, target_centroid);
00330   
00331         // build the 3x3 matrix M
00332         Mat3d M = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
00333         
00334         for (i = 0; i < nPoints; i++)
00335         {
00336                 Vec3d a, b;
00337                 Mat3d matrix;
00338 
00339                 Math3d::SubtractVecVec(pSourcePoints[i], source_centroid, a);
00340                 Math3d::SubtractVecVec(pTargetPoints[i], target_centroid, b);
00341                     
00342                 // accumulate the products a * b^T into the matrix M
00343                 Math3d::MulVecTransposedVec(a, b, matrix);
00344                 Math3d::AddToMat(M, matrix);
00345         }
00346 
00347         // build the 4x4 matrix N
00348         double N0[4], N1[4], N2[4], N3[4];
00349         double *N[4] = { N0, N1, N2, N3 };
00350 
00351         for (i = 0; i < 4; i++)
00352         {
00353                 // fill N with zeros
00354                 N[i][0] = 0.0f;
00355                 N[i][1] = 0.0f;
00356                 N[i][2] = 0.0f;
00357                 N[i][3] = 0.0f;
00358         }
00359 
00360         // on-diagonal elements
00361         N[0][0] =  M.r1 + M.r5 + M.r9;
00362         N[1][1] =  M.r1 - M.r5 - M.r9;
00363         N[2][2] = -M.r1 + M.r5 - M.r9;
00364         N[3][3] = -M.r1 - M.r5 + M.r9;
00365 
00366         // off-diagonal elements
00367         N[0][1] = N[1][0] = M.r6 - M.r8;
00368         N[0][2] = N[2][0] = M.r7 - M.r3;
00369         N[0][3] = N[3][0] = M.r2 - M.r4;
00370 
00371         N[1][2] = N[2][1] = M.r2 + M.r4;
00372         N[1][3] = N[3][1] = M.r7 + M.r3;
00373         N[2][3] = N[3][2] = M.r6 + M.r8;
00374 
00375         double eigenvalues[4];
00376         double eigenvectors0[4], eigenvectors1[4], eigenvectors2[4], eigenvectors3[4];
00377         double *eigenvectors[4] = { eigenvectors0, eigenvectors1, eigenvectors2, eigenvectors3 };
00378 
00379         // eigen-decompose N (is symmetric)
00380         Jacobi4(N, eigenvalues, eigenvectors);
00381 
00382         // the eigenvector with the largest eigenvalue is the quaternion we want
00383         // (they are sorted in decreasing order for us by JacobiN)
00384         float w, x, y, z;
00385 
00386         // first: if points are collinear, choose the quaternion that 
00387         // results in the smallest rotation.
00388         if (eigenvalues[0] == eigenvalues[1] || nPoints == 2)
00389         {
00390                 Vec3d s0, t0, s1, t1;
00391                 Math3d::SetVec(s0, pSourcePoints[0]);
00392                 Math3d::SetVec(t0, pTargetPoints[0]);
00393                 Math3d::SetVec(s1, pSourcePoints[1]);
00394                 Math3d::SetVec(t1, pTargetPoints[1]);
00395 
00396                 Vec3d ds, dt;
00397                 Math3d::SubtractVecVec(s1, s0, ds);
00398                 Math3d::SubtractVecVec(t1, t0, dt);
00399                 Math3d::NormalizeVec(ds);
00400                 Math3d::NormalizeVec(dt);
00401   
00402                 // take dot & cross product
00403                 w = ds.x * dt.x + ds.y * dt.y + ds.z * dt.z;
00404                 x = ds.y * dt.z - ds.z * dt.y;
00405                 y = ds.z * dt.x - ds.x * dt.z;
00406                 z = ds.x * dt.y - ds.y * dt.x;
00407 
00408                 float r = sqrtf(x * x + y * y + z * z);
00409                 const float theta = atan2f(r, w);
00410 
00411                 // construct quaternion
00412                 w = cosf(0.5f * theta);
00413   
00414                 if (r != 0)
00415                 {
00416                         r = sinf(0.5f * theta) / r;
00417                         x = x * r;
00418                         y = y * r;
00419                         z = z * r;
00420                 }
00421                 else // rotation by 180 degrees: special case
00422                 {
00423                         // rotate around a vector perpendicular to ds
00424                         double ds_[3] = { ds.x, ds.y, ds.z };
00425                         double dt_[3];
00426                                                 
00427                         Perpendiculars(ds_, dt_, 0, 0);
00428                         
00429                         r = sinf(0.5f * theta);
00430                         x = float(dt_[0] * r);
00431                         y = float(dt_[1] * r);
00432                         z = float(dt_[2] * r);
00433                 }
00434         }
00435         else
00436         {
00437                 // points are not collinear
00438                 w = (float) eigenvectors[0][0];
00439                 x = (float) eigenvectors[1][0];
00440                 y = (float) eigenvectors[2][0];
00441                 z = (float) eigenvectors[3][0];
00442         }
00443 
00444         // convert quaternion to a rotation matrix
00445         const float ww = w * w;
00446         const float wx = w * x;
00447         const float wy = w * y;
00448         const float wz = w * z;
00449 
00450         const float xx = x * x;
00451         const float yy = y * y;
00452         const float zz = z * z;
00453 
00454         const float xy = x * y;
00455         const float xz = x * z;
00456         const float yz = y * z;
00457 
00458         rotation.r1 = ww + xx - yy - zz; 
00459         rotation.r4 = 2.0f * (wz + xy);
00460         rotation.r7 = 2.0f * (-wy + xz);
00461 
00462         rotation.r2 = 2.0f * (-wz + xy);  
00463         rotation.r5 = ww - xx + yy - zz;
00464         rotation.r8 = 2.0f * (wx + yz);
00465 
00466         rotation.r3 = 2.0f * (wy + xz);
00467         rotation.r6 = 2.0f * (-wx + yz);
00468         rotation.r9 = ww - xx - yy + zz;
00469 
00470         // the translation is given by the difference of the transformed
00471         // source centroid and the target centroid
00472         Vec3d temp;
00473         Math3d::MulMatVec(rotation, source_centroid, temp);
00474         Math3d::SubtractVecVec(target_centroid, temp, translation);
00475         
00476         return true;
00477 }


asr_ivt
Author(s): Allgeyer Tobias, Hutmacher Robin, Kleinert Daniel, Meißner Pascal, Scholz Jonas, Stöckle Patrick
autogenerated on Thu Jun 6 2019 21:46:57