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
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #include <new>
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
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
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
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
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
00136 for (l = 0; l < j; l++)
00137 {
00138 JACOBI_ROTATE(a, l, j, l, k);
00139 }
00140
00141
00142 for (l = j + 1; l < k; l++)
00143 {
00144 JACOBI_ROTATE(a, j, l, l, k);
00145 }
00146
00147
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
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
00200
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
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
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
00311
00312
00313
00314
00315
00316
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
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
00343 Math3d::MulVecTransposedVec(a, b, matrix);
00344 Math3d::AddToMat(M, matrix);
00345 }
00346
00347
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
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
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
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
00380 Jacobi4(N, eigenvalues, eigenvectors);
00381
00382
00383
00384 float w, x, y, z;
00385
00386
00387
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
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
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
00422 {
00423
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
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
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
00471
00472 Vec3d temp;
00473 Math3d::MulMatVec(rotation, source_centroid, temp);
00474 Math3d::SubtractVecVec(target_centroid, temp, translation);
00475
00476 return true;
00477 }