00001
00002 #include "mbl_thin_plate_spline_3d.h"
00003
00004
00005
00006
00007
00008 #include <vcl_cmath.h>
00009 #include <vcl_cstdlib.h>
00010 #include <vsl/vsl_indent.h>
00011 #include <vsl/vsl_vector_io.h>
00012 #include <vnl/vnl_math.h>
00013 #include <vnl/algo/vnl_svd.h>
00014 #include <vnl/io/vnl_io_vector.h>
00015 #include <vnl/io/vnl_io_matrix.h>
00016 #include <vgl/vgl_vector_3d.h>
00017 #include <vgl/io/vgl_io_point_3d.h>
00018 #include <mbl/mbl_matxvec.h>
00019
00020
00021
00022
00023
00024
00025
00026
00027 mbl_thin_plate_spline_3d::mbl_thin_plate_spline_3d()
00028 : Wx_(0),Wy_(0),Wz_(0),
00029 Ax0_(0),AxX_(1),AxY_(0),AxZ_(0),
00030 Ay0_(0),AyX_(0),AyY_(1),AyZ_(0),
00031 Az0_(0),AzX_(0),AzY_(0),AzZ_(1),
00032 energy_x_(0),energy_y_(0),energy_z_(0)
00033 {
00034 }
00035
00036
00037
00038
00039
00040 mbl_thin_plate_spline_3d::~mbl_thin_plate_spline_3d()
00041 {
00042 }
00043
00044
00045
00046 inline double r2lnr(const vgl_vector_3d<double>& pt)
00047 {
00048 double r2 = pt.x() * pt.x() + pt.y() * pt.y() + pt.z() * pt.z();
00049 if (r2>1e-8) return 0.5 * r2 * vcl_log(r2);
00050 else return 0;
00051 }
00052
00053 inline double r2lnr(double x, double y, double z)
00054 {
00055 double r2 = x * x + y * y + z*z;
00056 if (r2>1e-8) return 0.5 * r2 * vcl_log(r2);
00057 else return 0;
00058 }
00059
00060
00061
00062
00063 static void build_K_part(vnl_matrix<double>& L,
00064 const vcl_vector<vgl_point_3d<double> >& pts)
00065 {
00066 unsigned int n = pts.size();
00067 if ( (L.rows()!=n+4) | (L.columns()!=n+4) ) L.set_size(n+4,n+4);
00068
00069 const vgl_point_3d<double> * pts_data = &pts[0];
00070 double** K_data = L.data_array();
00071
00072
00073 for (unsigned int i=0;i<n;i++)
00074 K_data[i][i] = 0;
00075
00076 for (unsigned int i=1;i<n;i++)
00077 for (unsigned int j=0;j<i;j++)
00078 {
00079 K_data[i][j] = K_data[j][i] = r2lnr(pts_data[i]-pts_data[j]);
00080 }
00081 }
00082
00083
00084
00085
00086
00087
00088
00089
00090 static void build_L(vnl_matrix<double>& L, const vcl_vector<vgl_point_3d<double> >& pts)
00091 {
00092 int i,j;
00093
00094 build_K_part(L,pts);
00095
00096 int n = pts.size();
00097
00098 const vgl_point_3d<double> * pts_data = &pts[0];
00099 double** L_data = L.data_array();
00100
00101
00102
00103 for (i=0;i<n;i++)
00104 {
00105 L_data[i][n] = 1;
00106 L_data[i][n+1] = pts_data[i].x();
00107 L_data[i][n+2] = pts_data[i].y();
00108 L_data[i][n+3] = pts_data[i].z();
00109
00110 L_data[n][i] = 1;
00111 L_data[n+1][i] = pts_data[i].x();
00112 L_data[n+2][i] = pts_data[i].y();
00113 L_data[n+3][i] = pts_data[i].z();
00114 }
00115
00116
00117 for (i=n;i<n+4;i++)
00118 for (j=n;j<n+4;j++)
00119 L_data[i][j] = 0;
00120 }
00121
00122
00123 void mbl_thin_plate_spline_3d::build_pure_affine(
00124 const vcl_vector<vgl_point_3d<double> >& source_pts,
00125 const vcl_vector<vgl_point_3d<double> >& dest_pts)
00126 {
00127 int n=source_pts.size();
00128 L_inv_.set_size(0,0);
00129 if (n==0)
00130 {
00131
00132 Ax0_ = 0;
00133 Ay0_ = 0;
00134 Az0_ = 0;
00135 AxX_ = 1; AxY_ = 0; AxZ_ = 0;
00136 AyX_ = 0; AyY_ = 1; AyZ_ = 0;
00137 AzX_ = 0; AzY_ = 0; AzZ_ = 1;
00138
00139 Wx_.set_size(0);
00140 Wy_.set_size(0);
00141 Wz_.set_size(0);
00142
00143 src_pts_.resize(0);
00144
00145 return;
00146 }
00147
00148 if (n==1)
00149 {
00150
00151 Ax0_ = dest_pts[0].x() - source_pts[0].x();
00152 Ay0_ = dest_pts[0].y() - source_pts[0].y();
00153 Az0_ = dest_pts[0].z() - source_pts[0].z();
00154 Wx_.set_size(0);
00155 Wy_.set_size(0);
00156 Wz_.set_size(0);
00157 AxX_ = 1; AxY_ = 0; AxZ_ = 0;
00158 AyX_ = 0; AyY_ = 1; AyZ_ = 0;
00159 AzX_ = 0; AzY_ = 0; AzZ_ = 1;
00160 src_pts_.resize(0);
00161
00162 return;
00163 }
00164 if (n>=2)
00165 {
00166 vcl_cerr<<"mbl_thin_plate_spline_3d::build_pure_affine() Incomplete. sorry.\n";
00167 vcl_abort();
00168 }
00169 }
00170
00171
00172 void mbl_thin_plate_spline_3d::set_params(const vnl_vector<double>& W1,
00173 const vnl_vector<double>& W2,
00174 const vnl_vector<double>& W3)
00175 {
00176 int n = W1.size()-4;
00177
00178 if (int(Wx_.size()) < n) Wx_.set_size(n);
00179 if (int(Wy_.size()) < n) Wy_.set_size(n);
00180 if (int(Wz_.size()) < n) Wz_.set_size(n);
00181
00182 double *Wx_data=Wx_.data_block();
00183 double *Wy_data=Wy_.data_block();
00184 double *Wz_data=Wz_.data_block();
00185 const double *W1_data=W1.data_block();
00186 const double *W2_data=W2.data_block();
00187 const double *W3_data=W3.data_block();
00188
00189 for (int i=0;i<n;i++)
00190 {
00191 Wx_data[i] = W1_data[i];
00192 Wy_data[i] = W2_data[i];
00193 Wz_data[i] = W3_data[i];
00194 }
00195
00196 Ax0_ = W1_data[n];
00197 AxX_ = W1_data[n+1];
00198 AxY_ = W1_data[n+2];
00199 AxZ_ = W1_data[n+3];
00200
00201 Ay0_ = W2_data[n];
00202 AyX_ = W2_data[n+1];
00203 AyY_ = W2_data[n+2];
00204 AyZ_ = W2_data[n+3];
00205
00206 Az0_ = W3_data[n];
00207 AzX_ = W3_data[n+1];
00208 AzY_ = W3_data[n+2];
00209 AzZ_ = W3_data[n+3];
00210 }
00211
00212 void mbl_thin_plate_spline_3d::compute_energy(vnl_vector<double>& W1,
00213 vnl_vector<double>& W2,
00214 vnl_vector<double>& W3,
00215 const vnl_matrix<double>& L)
00216 {
00217 int n = W1.size()-3;
00218 double *W1_data=W1.data_block();
00219 double *W2_data=W2.data_block();
00220 double *W3_data=W3.data_block();
00221
00222
00223 for (int i = n;i<=n+3;++i)
00224 {
00225 W1_data[i]=0.0;
00226 W2_data[i]=0.0;
00227 W3_data[i]=0.0;
00228 }
00229
00230
00231 vnl_vector<double> LW;
00232 mbl_matxvec_prod_mv(L,W1,LW);
00233 energy_x_ = dot_product(W1,LW) / (8*vnl_math::pi);
00234
00235 mbl_matxvec_prod_mv(L,W2,LW);
00236 energy_y_ = dot_product(W2,LW) / (8*vnl_math::pi);
00237
00238 mbl_matxvec_prod_mv(L,W3,LW);
00239 energy_z_ = dot_product(W3,LW) / (8*vnl_math::pi);
00240 }
00241
00242 void mbl_thin_plate_spline_3d::set_up_rhs(vnl_vector<double>& Bx,
00243 vnl_vector<double>& By,
00244 vnl_vector<double>& Bz,
00245 const vcl_vector<vgl_point_3d<double> >& dest_pts)
00246 {
00247 int n =dest_pts.size();
00248
00249 Bx.set_size(n+4);
00250 By.set_size(n+4);
00251 Bz.set_size(n+4);
00252 double* Bx_data=Bx.data_block();
00253 double* By_data=By.data_block();
00254 double* Bz_data=Bz.data_block();
00255 const vgl_point_3d<double> *d_pts_data=&dest_pts[0];
00256
00257 for (int i=0;i<n;i++)
00258 {
00259 Bx_data[i] = d_pts_data[i].x();
00260 By_data[i] = d_pts_data[i].y();
00261 Bz_data[i] = d_pts_data[i].z();
00262 }
00263 for (int i=n;i<n+4;i++)
00264 {
00265 Bx_data[i] = 0;
00266 By_data[i] = 0;
00267 Bz_data[i] = 0;
00268 }
00269 }
00270
00271 void mbl_thin_plate_spline_3d::build(const vcl_vector<vgl_point_3d<double> >& source_pts,
00272 const vcl_vector<vgl_point_3d<double> >& dest_pts,
00273 bool compute_the_energy)
00274 {
00275
00276
00277 unsigned int n=source_pts.size();
00278 if (dest_pts.size() != n)
00279 {
00280 vcl_cerr<<"mbl_thin_plate_spline_3d::build - incompatible number of points.\n";
00281 vcl_abort();
00282 }
00283
00284 L_inv_.set_size(0,0);
00285
00286 if (n<2)
00287 {
00288 build_pure_affine(source_pts,dest_pts);
00289 return;
00290 }
00291
00292 src_pts_ = source_pts;
00293
00294 vnl_matrix<double> L;
00295 vnl_vector<double> Bx(n+4), W1(n+4);
00296 vnl_vector<double> By(n+4), W2(n+4);
00297 vnl_vector<double> Bz(n+4), W3(n+4);
00298
00299 build_L(L,source_pts);
00300
00301 set_up_rhs(Bx,By,Bz,dest_pts);
00302
00303
00304
00305
00306 {
00307 vnl_svd<double> svd(L);
00308 svd.solve(Bx.data_block(),W1.data_block());
00309 svd.solve(By.data_block(),W2.data_block());
00310 svd.solve(Bz.data_block(),W3.data_block());
00311 }
00312
00313 set_params(W1,W2,W3);
00314 if (compute_the_energy)
00315 compute_energy(W1,W2,W3,L);
00316 }
00317
00318
00319
00320
00321 void mbl_thin_plate_spline_3d::set_source_pts(const vcl_vector<vgl_point_3d<double> >& source_pts)
00322 {
00323 unsigned int n=source_pts.size();
00324 src_pts_ = source_pts;
00325
00326 if (n<2)
00327 {
00328 L_inv_.set_size(0,0);
00329 return;
00330 }
00331
00332 vnl_matrix<double> L;
00333 build_L(L,source_pts);
00334
00335
00336
00337
00338 {
00339 vnl_svd<double> svd(L);
00340 L_inv_ = svd.inverse();
00341 }
00342 }
00343
00344
00345 void mbl_thin_plate_spline_3d::build(const vcl_vector<vgl_point_3d<double> >& dest_pts)
00346 {
00347 unsigned int n=src_pts_.size();
00348 if (dest_pts.size() != n)
00349 {
00350 vcl_cerr<<"mbl_thin_plate_spline_3d::build - incompatible number of points.\n";
00351 vcl_abort();
00352 }
00353
00354 if (n<2)
00355 {
00356 build_pure_affine(src_pts_,dest_pts);
00357 return;
00358 }
00359
00360 vnl_vector<double> Bx(n+4), W1(n+4);
00361 vnl_vector<double> By(n+4), W2(n+4);
00362 vnl_vector<double> Bz(n+4), W3(n+4);
00363
00364 set_up_rhs(Bx,By,Bz,dest_pts);
00365
00366 mbl_matxvec_prod_mv(L_inv_,Bx,W1);
00367 mbl_matxvec_prod_mv(L_inv_,By,W2);
00368 mbl_matxvec_prod_mv(L_inv_,Bz,W3);
00369
00370 set_params(W1,W2,W3);
00371 energy_x_ = -1;
00372 energy_y_ = -1;
00373 energy_z_ = -1;
00374 }
00375
00376
00377 vgl_point_3d<double> mbl_thin_plate_spline_3d::operator()(double x, double y, double z) const
00378 {
00379 unsigned int n = src_pts_.size();
00380
00381 double x_sum = Ax0_ + AxX_ * x + AxY_ * y + AxZ_ * z;
00382 double y_sum = Ay0_ + AyX_ * x + AyY_ * y + AyZ_ * z;
00383 double z_sum = Az0_ + AzX_ * x + AzY_ * y + AzZ_ * z;
00384
00385 if (n<=4)
00386 return vgl_point_3d<double>(x_sum,y_sum,z_sum);
00387
00388 const vgl_point_3d<double> * pts_data = &src_pts_[0];
00389 const double* Wx_data = Wx_.data_block();
00390 const double* Wy_data = Wy_.data_block();
00391 const double* Wz_data = Wz_.data_block();
00392
00393 for (unsigned int i=0;i<n;i++)
00394 {
00395 double Ui = r2lnr(x - pts_data[i].x(), y - pts_data[i].y(), z - pts_data[i].z() );
00396 x_sum += (Ui * Wx_data[i]);
00397 y_sum += (Ui * Wy_data[i]);
00398 z_sum += (Ui * Wz_data[i]);
00399 }
00400
00401 return vgl_point_3d<double>(x_sum,y_sum,z_sum);
00402 }
00403
00404
00405
00406
00407
00408 short mbl_thin_plate_spline_3d::version_no() const
00409 {
00410 return 1;
00411 }
00412
00413
00414
00415
00416
00417
00418
00419 void mbl_thin_plate_spline_3d::print_summary(vcl_ostream& os) const
00420 {
00421 os<<"\nfx: "<<Ax0_<<" + "<<AxX_<<"*x + "<<AxY_
00422 <<"*y + "<<AxZ_<<"*z Nonlinear terms:";
00423 for (unsigned int i=0;i<Wx_.size();++i)
00424 os<<' '<<Wx_[i];
00425 os<<"\nfy: "<<Ay0_<<" + "<<AyX_<<"*x + "<<AyY_
00426 <<"*y + "<<AyZ_<<"*z Nonlinear terms:";
00427 for (unsigned int i=0;i<Wy_.size();++i)
00428 os<<' '<<Wy_[i];
00429 os<<"\nfy: "<<Az0_<<" + "<<AzX_<<"*x + "<<AzY_
00430 <<"*y + "<<AzZ_<<"*z Nonlinear terms:";
00431 for (unsigned int i=0;i<Wz_.size();++i)
00432 os<<' '<<Wz_[i];
00433 os<<'\n';
00434 }
00435
00436
00437
00438
00439
00440
00441 void mbl_thin_plate_spline_3d::b_write(vsl_b_ostream& bfs) const
00442 {
00443 vsl_b_write(bfs,version_no());
00444 vsl_b_write(bfs,Wx_); vsl_b_write(bfs,Wy_);vsl_b_write(bfs,Wz_);
00445 vsl_b_write(bfs,Ax0_); vsl_b_write(bfs,AxX_);
00446 vsl_b_write(bfs,AxY_); vsl_b_write(bfs,AxZ_);
00447 vsl_b_write(bfs,Ay0_); vsl_b_write(bfs,AyX_);
00448 vsl_b_write(bfs,AyY_); vsl_b_write(bfs,AyZ_);
00449 vsl_b_write(bfs,Az0_); vsl_b_write(bfs,AzX_);
00450 vsl_b_write(bfs,AzY_); vsl_b_write(bfs,AzZ_);
00451 vsl_b_write(bfs,energy_x_);
00452 vsl_b_write(bfs,energy_y_);
00453 vsl_b_write(bfs,energy_z_);
00454 vsl_b_write(bfs,src_pts_);
00455 vsl_b_write(bfs,L_inv_);
00456 }
00457
00458
00459
00460
00461
00462
00463 void mbl_thin_plate_spline_3d::b_read(vsl_b_istream& bfs)
00464 {
00465 if (!bfs) return;
00466
00467 short version;
00468 vsl_b_read(bfs,version);
00469 switch (version)
00470 {
00471 case (1):
00472 vsl_b_read(bfs,Wx_); vsl_b_read(bfs,Wy_);vsl_b_read(bfs,Wz_);
00473 vsl_b_read(bfs,Ax0_); vsl_b_read(bfs,AxX_);
00474 vsl_b_read(bfs,AxY_); vsl_b_read(bfs,AxZ_);
00475 vsl_b_read(bfs,Ay0_); vsl_b_read(bfs,AyX_);
00476 vsl_b_read(bfs,AyY_); vsl_b_read(bfs,AyZ_);
00477 vsl_b_read(bfs,Az0_); vsl_b_read(bfs,AzX_);
00478 vsl_b_read(bfs,AzY_); vsl_b_read(bfs,AzZ_);
00479 vsl_b_read(bfs,energy_x_);
00480 vsl_b_read(bfs,energy_y_);
00481 vsl_b_read(bfs,energy_z_);
00482 vsl_b_read(bfs,src_pts_);
00483 vsl_b_read(bfs,L_inv_);
00484 break;
00485 default:
00486 vcl_cerr << "I/O ERROR: vsl_b_read(vsl_b_istream&, mbl_thin_plate_spline_3d &)\n"
00487 << " Unknown version number "<< version << '\n';
00488 bfs.is().clear(vcl_ios::badbit);
00489 return;
00490 }
00491 }
00492
00493
00494 bool mbl_thin_plate_spline_3d::operator==(const mbl_thin_plate_spline_3d& tps) const
00495 {
00496 if (&tps==this) return true;
00497 if (vcl_fabs(Ax0_-tps.Ax0_)>1e-8) return false;
00498 if (vcl_fabs(AxX_-tps.AxX_)>1e-8) return false;
00499 if (vcl_fabs(AxY_-tps.AxY_)>1e-8) return false;
00500 if (vcl_fabs(AxZ_-tps.AxZ_)>1e-8) return false;
00501 if (vcl_fabs(Ay0_-tps.Ay0_)>1e-8) return false;
00502 if (vcl_fabs(AyX_-tps.AyX_)>1e-8) return false;
00503 if (vcl_fabs(AyY_-tps.AyY_)>1e-8) return false;
00504 if (vcl_fabs(AyZ_-tps.AyZ_)>1e-8) return false;
00505 if (vcl_fabs(Az0_-tps.Az0_)>1e-8) return false;
00506 if (vcl_fabs(AzX_-tps.AzX_)>1e-8) return false;
00507 if (vcl_fabs(AzY_-tps.AzY_)>1e-8) return false;
00508 if (vcl_fabs(AzZ_-tps.AzZ_)>1e-8) return false;
00509 if (vnl_vector_ssd(Wx_,tps.Wx_)>1e-6) return false;
00510 if (vnl_vector_ssd(Wy_,tps.Wy_)>1e-6) return false;
00511 if (vnl_vector_ssd(Wz_,tps.Wz_)>1e-6) return false;
00512 return true;
00513 }
00514
00515
00516
00517
00518
00519 void vsl_b_write(vsl_b_ostream& bfs, const mbl_thin_plate_spline_3d& b)
00520 {
00521 b.b_write(bfs);
00522 }
00523
00524
00525
00526
00527
00528 void vsl_b_read(vsl_b_istream& bfs, mbl_thin_plate_spline_3d& b)
00529 {
00530 b.b_read(bfs);
00531 }
00532
00533
00534
00535
00536
00537 vcl_ostream& operator<<(vcl_ostream& os,const mbl_thin_plate_spline_3d& b)
00538 {
00539 os << "mbl_thin_plate_spline_3d: ";
00540 vsl_indent_inc(os);
00541 b.print_summary(os);
00542 vsl_indent_dec(os);
00543 return os;
00544 }