core/vpgl/algo/vpgl_ortho_procrustes.cxx
Go to the documentation of this file.
00001 #include "vpgl_ortho_procrustes.h"
00002 //:
00003 // \file
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 //: only one constructor. X and Y must have dimensions 3 x N
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   //remove the centroid of both point sets
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   //Normalize X, Y by the average radius
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   //compute the mean square residual
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 }