Go to the documentation of this file.00001 #include "vpgl_ortho_procrustes.h"
00002
00003
00004 #include <vnl/vnl_matrix.h>
00005 #include <vnl/vnl_trace.h>
00006 #include <vnl/vnl_matrix_fixed.h>
00007 #include <vnl/vnl_vector_fixed.h>
00008 #include <vnl/vnl_det.h>
00009 #include <vnl/algo/vnl_svd.h>
00010
00011
00012 vpgl_ortho_procrustes::
00013 vpgl_ortho_procrustes(vnl_matrix<double> const& X,
00014 vnl_matrix<double> const& Y)
00015 : cannot_compute_(false), computed_(false), s_(1.0), residual_(0)
00016 {
00017 if (X.rows()!=3 || Y.rows()!=3||X.columns()!=Y.columns()){
00018 cannot_compute_ = true;
00019 vcl_cout << "Fatal error in vpgl_ortho_procrustes - unmatched pointsets\n";
00020 return;
00021 }
00022 X_ = X;
00023 Y_ = Y;
00024 }
00025
00026 void vpgl_ortho_procrustes::compute()
00027 {
00028 unsigned N = X_.columns();
00029
00030 vnl_vector_fixed<double, 3> Cx, Cy;
00031 Cx.fill(0); Cy.fill(0);
00032 for (unsigned c = 0; c<N; ++c)
00033 {
00034 vnl_vector_fixed<double, 3> vx, vy;
00035 for (unsigned r = 0; r<3; ++r)
00036 {
00037 vx[r] = X_[r][c];
00038 vy[r] = Y_[r][c];
00039 }
00040 Cx += vx;
00041 Cy += vy;
00042 }
00043 Cx/=N; Cy/=N;
00044 vnl_matrix<double> Xm(3, N), Ym(3,N);
00045 double smx=0, smy=0;
00046 for (unsigned c = 0; c<N; ++c)
00047 {
00048 vnl_vector_fixed<double, 3> Sx, Sy;
00049 for (unsigned r = 0; r<3; ++r)
00050 {
00051 Xm[r][c] = X_[r][c]-Cx[r];
00052 Ym[r][c] = Y_[r][c]-Cy[r];
00053 Sx[r] = Xm[r][c];
00054 Sy[r] = Ym[r][c];
00055 }
00056 smx += Sx.squared_magnitude();
00057 smy += Sy.squared_magnitude();
00058 }
00059
00060 double neu = vnl_trace<double, 3, 3>(Xm*(Xm.transpose()));
00061 double den = vnl_trace<double, 3, 3>(Ym*(Ym.transpose()));
00062 if (den!=0)
00063 s_ = vcl_sqrt(neu/den);
00064
00065
00066 double sigma_x = vcl_sqrt(smx/N), sigma_y = vcl_sqrt(smy/N);
00067 Xm /= sigma_x;
00068 Ym /= sigma_y;
00069
00070 vnl_matrix<double> Xt = Xm.transpose();
00071 vnl_matrix_fixed<double, 3,3> M = Ym*Xt;
00072 vnl_svd<double> SVD(M.as_ref());
00073 vnl_matrix_fixed<double, 3,3> U = SVD.U();
00074 vnl_matrix_fixed<double, 3,3> V = SVD.V();
00075 vnl_matrix_fixed<double, 3,3> Ut = U.transpose();
00076 vnl_matrix_fixed<double, 3, 3> T, temp;
00077 temp = V*Ut;
00078 T.fill(0);
00079 T[0][0]=1.0;
00080 T[1][1]=1.0;
00081 T[2][2]=vnl_det<double>(temp);
00082 vnl_matrix_fixed<double, 3,3> rr = V*T*Ut;
00083 R_ = vgl_rotation_3d<double>(rr);
00084 t_ = (1.0/s_)*Cx - rr*Cy;
00085
00086 residual_ = 0;
00087 for (unsigned c = 0; c<N; ++c)
00088 {
00089 vnl_vector_fixed<double, 3> x, y, diff;
00090 for (unsigned r = 0; r<3; ++r)
00091 {
00092 x[r]=X_[r][c];
00093 y[r]=Y_[r][c];
00094 }
00095 diff = s_*(rr*y + t_) - x;
00096 residual_ += diff.squared_magnitude();
00097 }
00098 residual_ /= (3*N);
00099 computed_ = true;
00100 }
00101
00102 vgl_rotation_3d<double> vpgl_ortho_procrustes::R()
00103 {
00104 if (!computed_&&!cannot_compute_)
00105 this->compute();
00106 return R_;
00107 }
00108
00109 double vpgl_ortho_procrustes::s()
00110 {
00111 if (!computed_&&!cannot_compute_)
00112 this->compute();
00113 return s_;
00114 }
00115
00116
00117 double vpgl_ortho_procrustes::residual_mean_sq_error()
00118 {
00119 if (!computed_&&!cannot_compute_)
00120 this->compute();
00121 return residual_;
00122 }
00123
00124 vnl_vector_fixed<double, 3> vpgl_ortho_procrustes::t()
00125 {
00126 if (!computed_&&!cannot_compute_)
00127 this->compute();
00128 return t_;
00129 }